diff --git a/.env.template b/.env.template index 124ab4a52..ad4549c91 100644 --- a/.env.template +++ b/.env.template @@ -20,6 +20,17 @@ GITHUB_CALLBACK_URL="/api/auth/github/callback" GITHUB_CLIENT_ID=test GITHUB_CLIENT_SECRET=test +# Discord OAuth config +DISCORD_CALLBACK_URL="/api/auth/discordcallback" +DISCORD_CLIENT_ID=foo +DISCORD_CLIENT_SECRET=foo +DISCORD_BOT_TOKEN=foo +DISCORD_SERVER_ID=foo +DISCORD_VANDERBILT_ROLE=foo +DISCORD_HACKER_ROLE=foo +DISCORD_MENTOR_ROLE=foo +DISCORD_SPONSOR_ROLE=foo + BUCKET_NAME=foo # As per README, remove spaces in the below, i.e GCP_STORAGE_SERVICE_ACCOUNT='{"type":"service_account","project_id":"foo"...}' GCP_STORAGE_SERVICE_ACCOUNT='{ \ diff --git a/.eslintrc.js b/.eslintrc.js index 58f76ea2a..119b7fe58 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -60,6 +60,10 @@ module.exports = { 'no-use-before-define': [0], '@typescript-eslint/no-use-before-define': ['error'], '@typescript-eslint/explicit-module-boundary-types': [0], + 'promise/catch-or-return': [ + 2, + { allowFinally: true } + ] }, root: true, overrides: [ diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 00a53a5ce..249d6dc70 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -10,7 +10,7 @@ If you choose not to use `nvm`, you'll have to manually make sure that your `nod If you choose to use `nvm`, you can just run `nvm use`. -Run `./scripts/install.sh` from the top level of the Vaken repository. Note that the variables in +Run `./scripts/devEnv.sh` from the top level of the Vaken repository. Note that the variables in the new `.env` file will need to be changed to valid values. **Installing MongoDB:** diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 723142e5a..0ef3a188c 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -16,4 +16,4 @@ jobs: - uses: actions/setup-node@v1 with: node-version: '14' - - run: npm audit --audit-level=high --only=prod + - run: npm audit --audit-level=high --production diff --git a/.vscode/settings.json b/.vscode/settings.json index 867fe1e68..3dbabdb3a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,5 +24,8 @@ "[jsonc]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, - "deepscan.enable": true + "deepscan.enable": true, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } } diff --git a/README.md b/README.md index c4fe01503..d75de6966 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ A next-gen hackathon registration system. ## Contributing -All contributions are welcome. Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for setup and development instructions. +All contributions are welcome. Please read [CONTRIBUTING.md](.github/CONTRIBUTING.md) for setup and development instructions. ## Customizing for your event - constants: [./src/common/constants.json](./src/common/constants.json) diff --git a/package-lock.json b/package-lock.json index 9bff75494..d4dec33b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,14 +51,6 @@ } } }, - "@apollographql/apollo-tools": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.4.8.tgz", - "integrity": "sha512-W2+HB8Y7ifowcf3YyPHgDI05izyRtOeZ4MqIr7LbTArtmJ0ZHULWpn84SGMW7NAvTV1tFExpHlveHhnXuJfuGA==", - "requires": { - "apollo-env": "^0.6.5" - } - }, "@apollographql/graphql-playground-html": { "version": "1.6.26", "resolved": "https://registry.npmjs.org/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.26.tgz", @@ -67,6 +59,27 @@ "xss": "^1.0.6" } }, + "@apollographql/graphql-upload-8-fork": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-upload-8-fork/-/graphql-upload-8-fork-8.1.3.tgz", + "integrity": "sha512-ssOPUT7euLqDXcdVv3Qs4LoL4BPtfermW1IOouaqEmj36TpHYDmYDIbKoSQxikd9vtMumFnP87OybH7sC9fJ6g==", + "requires": { + "@types/express": "*", + "@types/fs-capacitor": "*", + "@types/koa": "*", + "busboy": "^0.3.1", + "fs-capacitor": "^2.0.4", + "http-errors": "^1.7.3", + "object-path": "^0.11.4" + }, + "dependencies": { + "fs-capacitor": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.4.tgz", + "integrity": "sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA==" + } + } + }, "@ardatan/aggregate-error": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@ardatan/aggregate-error/-/aggregate-error-0.0.6.tgz", @@ -644,11 +657,6 @@ "@babel/types": "^7.12.1" }, "dependencies": { - "@babel/parser": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.3.tgz", - "integrity": "sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw==" - }, "@babel/types": { "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.1.tgz", @@ -3092,6 +3100,11 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + }, + "ws": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", + "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==" } } }, @@ -3423,6 +3436,11 @@ "chalk": "^4.0.0" } }, + "@josephg/resolvable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@josephg/resolvable/-/resolvable-1.0.1.tgz", + "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==" + }, "@mdx-js/loader": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/loader/-/loader-1.6.22.tgz", @@ -7092,9 +7110,9 @@ } }, "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -9333,6 +9351,15 @@ "minimist": "^1.2.5" } }, + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -9418,9 +9445,9 @@ } }, "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -9663,6 +9690,12 @@ "repeat-string": "^1.6.1" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, "util.promisify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", @@ -9685,6 +9718,12 @@ "watchpack-chokidar2": "^2.0.1" } }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, "webpack": { "version": "4.46.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", @@ -9780,6 +9819,16 @@ } } }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", @@ -11678,17 +11727,6 @@ "@types/node": "*" } }, - "@types/graphql-upload": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/@types/graphql-upload/-/graphql-upload-8.0.4.tgz", - "integrity": "sha512-0TRyJD2o8vbkmJF8InppFcPVcXKk+Rvlg/xvpHBIndSJYpmDWfmtx/ZAtl4f3jR2vfarpTqYgj8MZuJssSoU7Q==", - "requires": { - "@types/express": "*", - "@types/fs-capacitor": "*", - "@types/koa": "*", - "graphql": "^15.3.0" - } - }, "@types/hast": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.1.tgz", @@ -11698,15 +11736,6 @@ "@types/unist": "*" } }, - "@types/helmet": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.48.tgz", - "integrity": "sha512-C7MpnvSDrunS1q2Oy1VWCY7CDWHozqSnM8P4tFeRTuzwqni+PYOjEredwcqWG+kLpYcgLsgcY3orHB54gbx2Jw==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, "@types/history": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.8.tgz", @@ -11947,6 +11976,7 @@ "version": "2.5.7", "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz", "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==", + "dev": true, "requires": { "@types/node": "*", "form-data": "^3.0.0" @@ -12999,44 +13029,6 @@ } } }, - "apollo-cache-control": { - "version": "0.11.5", - "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.11.5.tgz", - "integrity": "sha512-jvarfQhwDRazpOsmkt5Pd7qGFrtbL70zMbUZGqDhJSYpfqI672f7bXXc7O3vtpbD3qnS3XTBvK2kspX/Bdo0IA==", - "requires": { - "apollo-server-env": "^2.4.5", - "apollo-server-plugin-base": "^0.10.3" - } - }, - "apollo-datasource": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.7.2.tgz", - "integrity": "sha512-ibnW+s4BMp4K2AgzLEtvzkjg7dJgCaw9M5b5N0YKNmeRZRnl/I/qBTQae648FsRKgMwTbRQIvBhQ0URUFAqFOw==", - "requires": { - "apollo-server-caching": "^0.5.2", - "apollo-server-env": "^2.4.5" - } - }, - "apollo-env": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.6.5.tgz", - "integrity": "sha512-jeBUVsGymeTHYWp3me0R2CZRZrFeuSZeICZHCeRflHTfnQtlmbSXdy5E0pOyRM9CU4JfQkKDC98S1YglQj7Bzg==", - "requires": { - "@types/node-fetch": "2.5.7", - "core-js": "^3.0.1", - "node-fetch": "^2.2.0", - "sha.js": "^2.4.11" - } - }, - "apollo-graphql": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.6.0.tgz", - "integrity": "sha512-BxTf5LOQe649e9BNTPdyCGItVv4Ll8wZ2BKnmiYpRAocYEXAVrQPWuSr3dO4iipqAU8X0gvle/Xu9mSqg5b7Qg==", - "requires": { - "apollo-env": "^0.6.5", - "lodash.sortby": "^4.7.0" - } - }, "apollo-link": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.14.tgz", @@ -13090,74 +13082,203 @@ } }, "apollo-server-core": { - "version": "2.19.1", - "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.19.1.tgz", - "integrity": "sha512-5EVmcY8Ij7Ywwu+Ze4VaUhZBcxl8t5ztcSatJrKMd4HYlEHyaNGBV2itfpyqAthxfdMbGKqlpeCHmTGSqDcNpA==", - "requires": { - "@apollographql/apollo-tools": "^0.4.3", - "@apollographql/graphql-playground-html": "1.6.26", - "@types/graphql-upload": "^8.0.0", + "version": "2.25.2", + "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.25.2.tgz", + "integrity": "sha512-lrohEjde2TmmDTO7FlOs8x5QQbAS0Sd3/t0TaK2TWaodfzi92QAvIsq321Mol6p6oEqmjm8POIDHW1EuJd7XMA==", + "requires": { + "@apollographql/apollo-tools": "^0.5.0", + "@apollographql/graphql-playground-html": "1.6.27", + "@apollographql/graphql-upload-8-fork": "^8.1.3", + "@josephg/resolvable": "^1.0.0", "@types/ws": "^7.0.0", - "apollo-cache-control": "^0.11.5", - "apollo-datasource": "^0.7.2", - "apollo-graphql": "^0.6.0", - "apollo-reporting-protobuf": "^0.6.2", - "apollo-server-caching": "^0.5.2", - "apollo-server-env": "^2.4.5", - "apollo-server-errors": "^2.4.2", - "apollo-server-plugin-base": "^0.10.3", - "apollo-server-types": "^0.6.2", - "apollo-tracing": "^0.12.1", + "apollo-cache-control": "^0.14.0", + "apollo-datasource": "^0.9.0", + "apollo-graphql": "^0.9.0", + "apollo-reporting-protobuf": "^0.8.0", + "apollo-server-caching": "^0.7.0", + "apollo-server-env": "^3.1.0", + "apollo-server-errors": "^2.5.0", + "apollo-server-plugin-base": "^0.13.0", + "apollo-server-types": "^0.9.0", + "apollo-tracing": "^0.15.0", "async-retry": "^1.2.1", "fast-json-stable-stringify": "^2.0.0", - "graphql-extensions": "^0.12.7", - "graphql-tag": "^2.9.2", - "graphql-tools": "^4.0.0", - "graphql-upload": "^8.0.2", + "graphql-extensions": "^0.15.0", + "graphql-tag": "^2.11.0", + "graphql-tools": "^4.0.8", "loglevel": "^1.6.7", - "lru-cache": "^5.0.0", + "lru-cache": "^6.0.0", "sha.js": "^2.4.11", - "subscriptions-transport-ws": "^0.9.11", - "uuid": "^8.0.0", - "ws": "^6.0.0" + "subscriptions-transport-ws": "^0.9.19", + "uuid": "^8.0.0" }, "dependencies": { - "fs-capacitor": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.4.tgz", - "integrity": "sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA==" + "@apollo/protobufjs": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", + "integrity": "sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + } + }, + "@apollographql/apollo-tools": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.5.1.tgz", + "integrity": "sha512-ZII+/xUFfb9ezDU2gad114+zScxVFMVlZ91f8fGApMzlS1kkqoyLnC4AJaQ1Ya/X+b63I20B4Gd+eCL8QuB4sA==" }, - "graphql-upload": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-8.1.0.tgz", - "integrity": "sha512-U2OiDI5VxYmzRKw0Z2dmfk0zkqMRaecH9Smh1U277gVgVe9Qn+18xqf4skwr4YJszGIh7iQDZ57+5ygOK9sM/Q==", + "@apollographql/graphql-playground-html": { + "version": "1.6.27", + "resolved": "https://registry.npmjs.org/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.27.tgz", + "integrity": "sha512-tea2LweZvn6y6xFV11K0KC8ETjmm52mQrW+ezgB2O/aTQf8JGyFmMcRPFgUaQZeHbWdm8iisDC6EjOKsXu0nfw==", "requires": { - "busboy": "^0.3.1", - "fs-capacitor": "^2.0.4", - "http-errors": "^1.7.3", - "object-path": "^0.11.4" + "xss": "^1.0.8" } }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + }, + "apollo-cache-control": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.14.0.tgz", + "integrity": "sha512-qN4BCq90egQrgNnTRMUHikLZZAprf3gbm8rC5Vwmc6ZdLolQ7bFsa769Hqi6Tq/lS31KLsXBLTOsRbfPHph12w==", "requires": { - "yallist": "^3.0.2" + "apollo-server-env": "^3.1.0", + "apollo-server-plugin-base": "^0.13.0" } }, - "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "apollo-datasource": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.9.0.tgz", + "integrity": "sha512-y8H99NExU1Sk4TvcaUxTdzfq2SZo6uSj5dyh75XSQvbpH6gdAXIW9MaBcvlNC7n0cVPsidHmOcHOWxJ/pTXGjA==", "requires": { - "async-limiter": "~1.0.0" + "apollo-server-caching": "^0.7.0", + "apollo-server-env": "^3.1.0" } }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "apollo-graphql": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.9.3.tgz", + "integrity": "sha512-rcAl2E841Iko4kSzj4Pt3PRBitmyq1MvoEmpl04TQSpGnoVgl1E/ZXuLBYxMTSnEAm7umn2IsoY+c6Ll9U/10A==", + "requires": { + "core-js-pure": "^3.10.2", + "lodash.sortby": "^4.7.0", + "sha.js": "^2.4.11" + } + }, + "apollo-reporting-protobuf": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz", + "integrity": "sha512-B3XmnkH6Y458iV6OsA7AhfwvTgeZnFq9nPVjbxmLKnvfkEl8hYADtz724uPa0WeBiD7DSFcnLtqg9yGmCkBohg==", + "requires": { + "@apollo/protobufjs": "1.2.2" + } + }, + "apollo-server-caching": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.7.0.tgz", + "integrity": "sha512-MsVCuf/2FxuTFVhGLK13B+TZH9tBd2qkyoXKKILIiGcZ5CDUEBO14vIV63aNkMkS1xxvK2U4wBcuuNj/VH2Mkw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "apollo-server-env": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-3.1.0.tgz", + "integrity": "sha512-iGdZgEOAuVop3vb0F2J3+kaBVi4caMoxefHosxmgzAbbSpvWehB8Y1QiSyyMeouYC38XNVk5wnZl+jdGSsWsIQ==", + "requires": { + "node-fetch": "^2.6.1", + "util.promisify": "^1.0.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, + "apollo-server-errors": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.5.0.tgz", + "integrity": "sha512-lO5oTjgiC3vlVg2RKr3RiXIIQ5pGXBFxYGGUkKDhTud3jMIhs+gel8L8zsEjKaKxkjHhCQAA/bcEfYiKkGQIvA==" + }, + "apollo-server-plugin-base": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.13.0.tgz", + "integrity": "sha512-L3TMmq2YE6BU6I4Tmgygmd0W55L+6XfD9137k+cWEBFu50vRY4Re+d+fL5WuPkk5xSPKd/PIaqzidu5V/zz8Kg==", + "requires": { + "apollo-server-types": "^0.9.0" + } + }, + "apollo-server-types": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-0.9.0.tgz", + "integrity": "sha512-qk9tg4Imwpk732JJHBkhW0jzfG0nFsLqK2DY6UhvJf7jLnRePYsPxWfPiNkxni27pLE2tiNlCwoDFSeWqpZyBg==", + "requires": { + "apollo-reporting-protobuf": "^0.8.0", + "apollo-server-caching": "^0.7.0", + "apollo-server-env": "^3.1.0" + } + }, + "apollo-tracing": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.15.0.tgz", + "integrity": "sha512-UP0fztFvaZPHDhIB/J+qGuy6hWO4If069MGC98qVs0I8FICIGu4/8ykpX3X3K6RtaQ56EDAWKykCxFv4ScxMeA==", + "requires": { + "apollo-server-env": "^3.1.0", + "apollo-server-plugin-base": "^0.13.0" + } + }, + "core-js-pure": { + "version": "3.17.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.17.2.tgz", + "integrity": "sha512-2VV7DlIbooyTI7Bh+yzOOWL9tGwLnQKHno7qATE+fqZzDKYr6llVjVQOzpD/QLZFgXDPb8T71pJokHEZHEYJhQ==" + }, + "graphql-extensions": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.15.0.tgz", + "integrity": "sha512-bVddVO8YFJPwuACn+3pgmrEg6I8iBuYLuwvxiE+lcQQ7POotVZxm2rgGw0PvVYmWWf3DT7nTVDZ5ROh/ALp8mA==", + "requires": { + "@apollographql/apollo-tools": "^0.5.0", + "apollo-server-env": "^3.1.0", + "apollo-server-types": "^0.9.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } } } }, @@ -13168,13 +13289,37 @@ "requires": { "node-fetch": "^2.1.2", "util.promisify": "^1.0.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } } }, - "apollo-server-errors": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.4.2.tgz", - "integrity": "sha512-FeGxW3Batn6sUtX3OVVUm7o56EgjxDlmgpTLNyWcLb0j6P8mw9oLNyAm3B+deHA4KNdNHO5BmHS2g1SJYjqPCQ==" - }, "apollo-server-express": { "version": "2.19.1", "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.19.1.tgz", @@ -13212,14 +13357,6 @@ } } }, - "apollo-server-plugin-base": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.10.3.tgz", - "integrity": "sha512-NCLOsk9Jsd8oLvefkQvROdMDQvnHnzbzz3MPCqEYjCOEv0YBM8T77D0wCwbcViDS2M5p0W6un2ub9s/vU71f7Q==", - "requires": { - "apollo-server-types": "^0.6.2" - } - }, "apollo-server-types": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-0.6.2.tgz", @@ -13230,15 +13367,6 @@ "apollo-server-env": "^2.4.5" } }, - "apollo-tracing": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.12.1.tgz", - "integrity": "sha512-qdkUjW+pOaidGOSITypeYE288y28HkPmGNpUtyQSOeTxgqXHtQX3TDWiOJ2SmrLH08xdSwfvz9o5KrTq4PdISg==", - "requires": { - "apollo-server-env": "^2.4.5", - "apollo-server-plugin-base": "^0.10.3" - } - }, "apollo-utilities": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.4.tgz", @@ -13488,12 +13616,6 @@ "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=", "dev": true }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -13786,7 +13908,8 @@ "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true }, "async-retry": { "version": "1.3.1", @@ -13861,9 +13984,9 @@ } }, "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -15081,24 +15204,6 @@ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "dev": true }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - } - } - }, "camelize": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", @@ -15434,18 +15539,6 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" }, - "clipboard": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz", - "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==", - "dev": true, - "optional": true, - "requires": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -16212,7 +16305,8 @@ "core-js": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.1.tgz", - "integrity": "sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg==" + "integrity": "sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg==", + "dev": true }, "core-js-compat": { "version": "3.8.1", @@ -16631,6 +16725,13 @@ "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==", "requires": { "node-fetch": "2.6.1" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + } } }, "cross-spawn": { @@ -16996,15 +17097,6 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz", "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==" }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "^1.0.1" - } - }, "cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -17284,13 +17376,6 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, - "delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", - "dev": true, - "optional": true - }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -20249,6 +20334,35 @@ "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", "node-fetch": "^2.3.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } } }, "gcp-metadata": { @@ -20270,6 +20384,35 @@ "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", "node-fetch": "^2.3.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } } } @@ -20298,6 +20441,35 @@ "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", "node-fetch": "^2.3.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } } } @@ -20474,9 +20646,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "requires": { "is-glob": "^4.0.1" } @@ -20570,16 +20742,6 @@ "slash": "^3.0.0" } }, - "good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", - "dev": true, - "optional": true, - "requires": { - "delegate": "^3.1.2" - } - }, "google-auth-library": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.1.tgz", @@ -20606,6 +20768,35 @@ "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", "node-fetch": "^2.3.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } } } @@ -20723,16 +20914,6 @@ } } }, - "graphql-extensions": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.12.7.tgz", - "integrity": "sha512-yc9qOmEmWVZNkux9m0eCiHdtYSwNZRHkFhgfKfDn4u/gpsJolft1iyMUADnG/eytiRW0CGZFBpZjHkJhpginuQ==", - "requires": { - "@apollographql/apollo-tools": "^0.4.3", - "apollo-server-env": "^2.4.5", - "apollo-server-types": "^0.6.2" - } - }, "graphql-request": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-3.4.0.tgz", @@ -20827,6 +21008,35 @@ "https-proxy-agent": "^5.0.0", "is-stream": "^2.0.0", "node-fetch": "^2.3.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } } } @@ -21259,9 +21469,9 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "helmet": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.3.1.tgz", - "integrity": "sha512-WsafDyKsIexB0+pUNkq3rL1rB5GVAghR68TP8ssM9DPEMzfBiluEQlVzJ/FEj6Vq2Ag3CNuxf7aYMjXrN0X49Q==" + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz", + "integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==" }, "highlight.js": { "version": "10.3.1", @@ -21732,9 +21942,9 @@ "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" }, "immer": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", - "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==" + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.6.tgz", + "integrity": "sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ==" }, "immutable": { "version": "3.7.6", @@ -22128,12 +22338,6 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, - "is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "dev": true - }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -22322,12 +22526,6 @@ "unc-path-regex": "^0.1.2" } }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, "is-whitespace-character": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", @@ -22380,6 +22578,35 @@ "requires": { "node-fetch": "^2.6.1", "whatwg-fetch": "^3.4.1" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } } }, "isomorphic-form-data": { @@ -24260,16 +24487,6 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - } - }, "lower-case": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", @@ -24356,12 +24573,6 @@ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, "map-or-similar": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", @@ -24512,114 +24723,6 @@ "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", "optional": true }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - } - } - }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -25233,9 +25336,33 @@ } }, "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } }, "node-forge": { "version": "0.10.0", @@ -25436,9 +25563,9 @@ "dev": true }, "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" }, "npm-run-path": { "version": "2.0.2", @@ -26259,9 +26386,9 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-root": { "version": "0.1.1", @@ -26593,9 +26720,9 @@ } }, "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -26725,9 +26852,9 @@ } }, "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -26896,13 +27023,10 @@ "dev": true }, "prismjs": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", - "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", - "dev": true, - "requires": { - "clipboard": "^2.0.0" - } + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.24.1.tgz", + "integrity": "sha512-mNPsedLuk90RVJioIky8ANZEwYm5w9LcvCXrxHlwf4fNVSn8jEipMybMkWUyyF0JhnC+C4VcOVSBuHRKs1L5Ow==", + "dev": true }, "process": { "version": "0.11.10", @@ -27646,6 +27770,12 @@ "worker-rpc": "^0.1.0" } }, + "immer": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", + "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==", + "dev": true + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -28205,36 +28335,15 @@ "minimatch": "3.0.4" } }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - }, - "dependencies": { - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - } - } - }, "refractor": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.3.1.tgz", - "integrity": "sha512-vaN6R56kLMuBszHSWlwTpcZ8KTMG6aUCok4GrxYDT20UIOXxOc5o6oDc8tNTzSlH3m2sI+Eu9Jo2kVdDcUTWYw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.4.0.tgz", + "integrity": "sha512-dBeD02lC5eytm9Gld2Mx0cMcnR+zhSnsTfPpWqFaMgUMJfC9A6bcN3Br/NaXrnBJcuxnLFR90k1jrkaSyV8umg==", "dev": true, "requires": { "hastscript": "^6.0.0", "parse-entities": "^2.0.0", - "prismjs": "~1.23.0" + "prismjs": "~1.24.0" } }, "regenerate": { @@ -28721,15 +28830,6 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, "replaceall": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/replaceall/-/replaceall-0.1.6.tgz", @@ -29210,13 +29310,6 @@ "resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz", "integrity": "sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg==" }, - "select": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", - "dev": true, - "optional": true - }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -30626,23 +30719,6 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" - }, - "dependencies": { - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - } - } - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -30714,29 +30790,21 @@ "integrity": "sha512-1UmkWmRwSPfzolKleyPjbZdBqkxSXv5ImqTP5WeSjWk0Z7IvEzsrYhrqinZfCg10eM1P6BEtFly8+puQJnN/0A==" }, "subscriptions-transport-ws": { - "version": "0.9.18", - "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.18.tgz", - "integrity": "sha512-tztzcBTNoEbuErsVQpTN2xUNN/efAZXyCyL5m3x4t6SKrEiTL2N8SaKWBFWM4u56pL79ULif3zjyeq+oV+nOaA==", + "version": "0.9.19", + "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz", + "integrity": "sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw==", "requires": { "backo2": "^1.0.2", "eventemitter3": "^3.1.0", "iterall": "^1.2.1", "symbol-observable": "^1.0.4", - "ws": "^5.2.0" + "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" }, "dependencies": { "symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "requires": { - "async-limiter": "~1.0.0" - } } } }, @@ -31075,6 +31143,33 @@ "base64-js": "^1.3.1", "ieee754": "^1.1.13" } + }, + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } } } }, @@ -31134,9 +31229,9 @@ "dev": true }, "tar": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", - "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -31190,6 +31285,35 @@ "node-fetch": "^2.6.1", "stream-events": "^1.0.5", "uuid": "^8.0.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } } }, "telejson": { @@ -31490,12 +31614,6 @@ "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", "dev": true }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, "trim-trailing-lines": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", @@ -31579,13 +31697,12 @@ } }, "ts-node-dev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.1.1.tgz", - "integrity": "sha512-kAO8LUZgXZSY0+PucMPsQ0Bbdv0x+lgbN7j8gcD4PuTI4uKC6YchekaspmYTBNilkiu+rQYkWJA7cK+Q8/B0tQ==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.1.8.tgz", + "integrity": "sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg==", "dev": true, "requires": { - "chokidar": "^3.4.0", - "dateformat": "~1.0.4-1.2.3", + "chokidar": "^3.5.1", "dynamic-dedupe": "^0.3.0", "minimist": "^1.2.5", "mkdirp": "^1.0.4", @@ -31597,22 +31714,47 @@ "tsconfig": "^7.0.0" }, "dependencies": { - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -32228,9 +32370,9 @@ } }, "url-parse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", - "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", + "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -33910,9 +34052,9 @@ } }, "ws": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", - "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==" + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.4.tgz", + "integrity": "sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg==" }, "xdg-basedir": { "version": "4.0.0", diff --git a/package.json b/package.json index 3e8827cfe..9ce0893d1 100644 --- a/package.json +++ b/package.json @@ -92,12 +92,13 @@ "gaxios": "^4.1.0", "googleapis": "^65.0.0", "graphql": "^15.4.0", - "helmet": "^4.3.1", - "immer": "^8.0.1", + "helmet": "^4.6.0", + "immer": "^9.0.6", "jsdom": "^16.4.0", "jszip": "^3.6.0", "mongodb": "^3.6.3", "mongodb-memory-server": "^6.9.2", + "node-fetch": "^2.6.5", "node-ical": "^0.12.5", "passport": "^0.4.1", "passport-azure-ad": "^4.3.0", @@ -143,7 +144,6 @@ "@types/express": "^4.17.9", "@types/express-session": "^1.17.3", "@types/faker": "^5.1.5", - "@types/helmet": "0.0.48", "@types/jest": "^26.0.19", "@types/mongodb": "^3.6.3", "@types/mongoose": "^5.10.3", @@ -201,7 +201,7 @@ "svg-inline-loader": "^0.8.2", "ts-jest": "^26.4.4", "ts-node": "^9.1.1", - "ts-node-dev": "^1.1.1", + "ts-node-dev": "^1.1.8", "typedoc": "^0.20.28", "typescript": "^4.1.3", "webpack": "^5.21.1", diff --git a/src/client/app.tsx b/src/client/app.tsx index 6b67af282..189b02d5e 100644 --- a/src/client/app.tsx +++ b/src/client/app.tsx @@ -8,7 +8,12 @@ import Frame from './routes/dashboard/Frame'; import { AuthContext } from './contexts/AuthContext'; import { useMeQuery } from './generated/graphql'; import 'react-toastify/dist/ReactToastify.css'; -import { ACCENT_COLOR, DARK_TEXT_COLOR, WARNING_COLOR } from './assets/strings.json'; +import { + ACCENT_COLOR_DARK, + DARK_TEXT_COLOR, + LIGHT_TEXT_COLOR, + WARNING_COLOR, +} from './assets/strings.json'; export const GlobalStyle = createGlobalStyle` ${reset} @@ -33,14 +38,18 @@ export const GlobalStyle = createGlobalStyle` font-family: 'Roboto', sans-serif !important; font-size: 1.1em !important; } + + .toast-emphasize { + font-weight: bold !important; + } `; export const theme: DefaultTheme = { borderRadius: '4px', colors: { - main: ACCENT_COLOR, + main: ACCENT_COLOR_DARK, darkTextColor: DARK_TEXT_COLOR, - lightTextColor: '#ffffff', + lightTextColor: LIGHT_TEXT_COLOR, secondary: '#ffffff', warning: WARNING_COLOR, }, diff --git a/src/client/assets/application.js b/src/client/assets/application.js index d868b1454..337c48a13 100644 --- a/src/client/assets/application.js +++ b/src/client/assets/application.js @@ -86,9 +86,9 @@ export const questions = [ }, { Component: Slider, - default: '2019', + default: '2025', fieldName: 'gradYear', - options: ['2021', '2022', '2023', '2024', 'Other'], + options: ['2022', '2023', '2024', '2025', 'Other'], other: true, title: 'Graduation Year', type: 'number', @@ -159,7 +159,7 @@ export const questions = [ Component: FileInput, fieldName: 'resume', note: '(pdf only) Your resume will be shared with sponsors', - title: 'Resume', + title: 'Résumé', }, { Component: CheckboxSansTitleCase, @@ -173,7 +173,7 @@ export const questions = [ Component: CheckboxSansTitleCase, fieldName: 'hackathonWaiver', options: [ - 'I have read and agree to the VandyHacks VII Waiver', + 'I have read and agree to the VandyHacks VIII Waiver', ], title: 'Hackathon Waiver', }, @@ -181,7 +181,7 @@ export const questions = [ Component: CheckboxSansTitleCase, fieldName: 'infoSharingConsent', options: [ - 'I authorize you to share my application/registration information for event administration, ranking, MLH administration, pre- and post-event informational emails, and occasional emails about hackathons in-line with the MLH Privacy Policy. I further agree to the terms of both the MLH Contest Terms and Conditions and the MLH Privacy Policy.', + 'I authorize you to share my application/registration information for event administration, ranking, MLH administration, pre- and post-event informational emails, and occasional emails about hackathons in line with the MLH Privacy Policy. I further agree to the terms of both the MLH Contest Terms and Conditions and the MLH Privacy Policy.', ], title: 'Information sharing consent', }, @@ -215,10 +215,12 @@ export const questions = [ placeholder: 'Nashville', }, { - Component: TextInput, + Component: AutoComplete, fieldName: 'state', placeholder: 'Tennessee', + note: 'If not found, please type the abbreviation.', optional: true, + options: import('./data/states.json'), title: 'State', }, { diff --git a/src/client/assets/data/states.json b/src/client/assets/data/states.json new file mode 100644 index 000000000..06cc7cdf4 --- /dev/null +++ b/src/client/assets/data/states.json @@ -0,0 +1,54 @@ +{ + "data": [ + "Alabama", + "Alaska", + "Arizona", + "Arkansas", + "California", + "Colorado", + "Connecticut", + "Delaware", + "Florida", + "Georgia", + "Hawaii", + "Idaho", + "Illinois", + "Indiana", + "Iowa", + "Kansas", + "Kentucky", + "Louisiana", + "Maine", + "Maryland", + "Massachusetts", + "Michigan", + "Minnesota", + "Mississippi", + "Missouri", + "Montana", + "Nebraska", + "Nevada", + "New Hampshire", + "New Jersey", + "New Mexico", + "New York", + "North Carolina", + "North Dakota", + "Ohio", + "Oklahoma", + "Oregon", + "Pennsylvania", + "Rhode Island", + "South Carolina", + "South Dakota", + "Tennessee", + "Texas", + "Utah", + "Vermont", + "Virginia", + "Washington", + "West Virginia", + "Wisconsin", + "Wyoming" + ] +} diff --git a/src/client/assets/img/VH_Space_Logo_Black.png b/src/client/assets/img/VH_Space_Logo_Black.png new file mode 100644 index 000000000..e1ec87ff9 Binary files /dev/null and b/src/client/assets/img/VH_Space_Logo_Black.png differ diff --git a/src/client/assets/img/VH_Space_Logo_White.png b/src/client/assets/img/VH_Space_Logo_White.png new file mode 100644 index 000000000..1cc864429 Binary files /dev/null and b/src/client/assets/img/VH_Space_Logo_White.png differ diff --git a/src/client/assets/routes.js b/src/client/assets/routes.js index 5e0c3ecf5..53c8ae715 100644 --- a/src/client/assets/routes.js +++ b/src/client/assets/routes.js @@ -4,11 +4,12 @@ import { HackerDash } from '../routes/dashboard/HackerDash'; import { Help } from '../routes/help/Help'; import { UserType } from '../generated/graphql'; import { packages } from '../plugins'; +import OrganizerDash from '../routes/dashboard/OrganizerDash'; const routes = [ { authLevel: [UserType.Organizer], - component: HackerDash, + component: OrganizerDash, displayText: 'Dashboard', path: '/dashboard', }, diff --git a/src/client/assets/strings.json b/src/client/assets/strings.json index 1c27d56f1..766e11361 100644 --- a/src/client/assets/strings.json +++ b/src/client/assets/strings.json @@ -1,6 +1,6 @@ { - "FULL_NAME": "VandyHacks VII", - "HACKATHON_TITLE": "VandyHacks VII", + "FULL_NAME": "VandyHacks VIII", + "HACKATHON_TITLE": "VandyHacks VIII", "WEBSITE_HTML_TITLE": "VandyHacks Application Portal", "DEADLINE": "October 2, 2020 at 12:00pm (CST)", "SHORTENED_HACKATHON_TITLE": "VH", @@ -11,10 +11,13 @@ "DARKEST_TEXT_COLOR": "#1A051D", "BASE_COLOR": "#B1D0FE", "ACCENT_COLOR": "#3148A1", + "ACCENT_COLOR_DARK": "#FF2D55", + "BACKGROUND_DARK": "#FFC1CA", + "BACKGROUND_DARK_SECONDARY": "#FBE4E8", "BASE_ACCENT_BLENDED": "#718CD0", "SIDEBAR_COLOR": "#202124", "WARNING_COLOR": "#FF647C", - "LIGHT_TEXT_COLOR": "#D0C9D6", + "LIGHT_TEXT_COLOR": "#FFFFFF", "SQUARE_LOGO_ALT_TEXT": "VH Logo", "HACKER_DASHBOARD_HEADER_TEXT": "Your application status:", "HACKER_TEAMS_ANNOUNCEMENT_TEXT": "Create a new team or join an existing one for the weekend! Due to prize arrangements, the maximum number of hackers per team is 4.\n\nThere will also be opportunities at the event to form teams.", diff --git a/src/client/components/Buttons/RadioSlider.tsx b/src/client/components/Buttons/RadioSlider.tsx index 57be90420..326942979 100644 --- a/src/client/components/Buttons/RadioSlider.tsx +++ b/src/client/components/Buttons/RadioSlider.tsx @@ -10,6 +10,7 @@ export interface Props { option2: string; option3: string; value: string; + confirmMessageFunc?: (input: string) => string; } interface SelectorProps { @@ -60,11 +61,11 @@ const Selector = styled('div')` const disabledColor = '#696969'; export const RadioSlider: FC = (props: Props) => { - const { option1, option2, option3, disable = false } = props; + const { option1, option2, option3, disable = false, confirmMessageFunc } = props; const [selected, setSelected] = useState(option2); const [width, setWidth] = useState(0); const [left, setLeft] = useState(0); - const [color, setColor] = useState(!disable ? STRINGS.ACCENT_COLOR : disabledColor); + const [color, setColor] = useState(!disable ? STRINGS.ACCENT_COLOR_DARK : disabledColor); const [isLoaded, setIsLoaded] = useState(false); const [option1Width, setOption1Width] = useState(0); const [option2Width, setOption2Width] = useState(0); @@ -100,7 +101,7 @@ export const RadioSlider: FC = (props: Props) => { case option2: setWidth(option2Width); setLeft(option1Width); - setColor(!disable ? STRINGS.ACCENT_COLOR : disabledColor); + setColor(!disable ? STRINGS.ACCENT_COLOR_DARK : disabledColor); break; case option3: setWidth(option3Width); @@ -134,6 +135,13 @@ export const RadioSlider: FC = (props: Props) => { const onClick = (event: React.MouseEvent): void => { const target = event.target as HTMLDivElement; if (!disable) { + if (confirmMessageFunc) { + // eslint-disable-next-line no-alert + const confirmed = window.confirm(confirmMessageFunc(target.id)); + if (!confirmed) { + return; + } + } toggle(target.id); if (typeof onChange === 'function') { onChange(target.id); diff --git a/src/client/components/Buttons/ToggleSwitch.tsx b/src/client/components/Buttons/ToggleSwitch.tsx index 3523aadc8..6865b314a 100644 --- a/src/client/components/Buttons/ToggleSwitch.tsx +++ b/src/client/components/Buttons/ToggleSwitch.tsx @@ -23,7 +23,7 @@ interface SliderProps { const Slider = styled('div')` ${({ checked }: SliderProps): string => checked - ? `background-color: ${STRINGS.ACCENT_COLOR}; &:before { transform: translateX(1.5rem); }` + ? `background-color: ${STRINGS.ACCENT_COLOR_DARK}; &:before { transform: translateX(1.5rem); }` : 'background-color: #ccc;'} position: absolute; cursor: pointer; diff --git a/src/client/components/Containers/Collapsible.tsx b/src/client/components/Containers/Collapsible.tsx index 71641d9ff..a7e363f8b 100644 --- a/src/client/components/Containers/Collapsible.tsx +++ b/src/client/components/Containers/Collapsible.tsx @@ -1,6 +1,6 @@ import styled from 'styled-components'; import React, { FC } from 'react'; -import { hexToRGB, Props as PopupProps } from './FloatingPopup'; +import { Props as PopupProps } from './FloatingPopup'; import UpArrow from '../../assets/img/up_arrow.svg'; import STRINGS from '../../assets/strings.json'; @@ -15,8 +15,8 @@ export const useMeasure = (): any => { const CollapsibleHeader = styled.button` border-radius: 8px; - background-color: #ecebed; - color: ${STRINGS.ACCENT_COLOR}; + background-color: ${STRINGS.BACKGROUND_DARK}; + color: ${STRINGS.ACCENT_COLOR_DARK}; cursor: pointer; padding: 14px 1.4rem; width: 100%; @@ -31,19 +31,17 @@ const CollapsibleHeader = styled.button` align-items: center; img { + // since img is up arrow but we want down arrow + transform: rotate(180deg); transition: 0.5s all; } img.open { - transform: rotate(-180deg); + transform: rotate(360deg); } `; const BGDiv = styled.div` - background-color: rgba( - ${({ backgroundColor }: PopupProps): string => - backgroundColor ? hexToRGB(backgroundColor) : '247, 245, 249'}, - ${({ backgroundOpacity = '1' }: PopupProps): string => backgroundOpacity} - ); + background-color: ${STRINGS.BACKGROUND_DARK_SECONDARY}; border-radius: 8px; width: 100%; `; diff --git a/src/client/components/Containers/FloatingPopup.tsx b/src/client/components/Containers/FloatingPopup.tsx index b40ab1093..82cc66d76 100644 --- a/src/client/components/Containers/FloatingPopup.tsx +++ b/src/client/components/Containers/FloatingPopup.tsx @@ -1,5 +1,6 @@ import styled from 'styled-components'; import { FlexStartColumn, ContainerProps } from './FlexContainers'; +import STRINGS from '../../assets/strings.json'; export const hexToRGB = (hex: string): string => { const r = parseInt(hex.slice(1, 3), 16); @@ -17,11 +18,7 @@ export interface Props extends ContainerProps { const FloatingPopup = styled(FlexStartColumn)` transition: ease-in-out all 1s; - background-color: rgba( - ${({ backgroundColor }: Props): string => - backgroundColor ? hexToRGB(backgroundColor) : '247, 245, 249'}, - ${({ backgroundOpacity = '1' }: Props): string => backgroundOpacity} - ); + background-color: ${STRINGS.BACKGROUND_DARK_SECONDARY}; border-radius: ${({ borderRadius = '8px' }: Props) => borderRadius}; padding: ${({ padding = '1.5rem' }: Props) => padding}; margin-bottom: ${({ marginBottom = '0' }: Props) => marginBottom}; diff --git a/src/client/components/Input/Checkbox.tsx b/src/client/components/Input/Checkbox.tsx index d5ae156bf..99a435f1d 100644 --- a/src/client/components/Input/Checkbox.tsx +++ b/src/client/components/Input/Checkbox.tsx @@ -27,7 +27,7 @@ const CheckboxContainer = styled.div` &:focus + label img { /* Color for keyboard users */ - box-shadow: 0 0 2px 2px ${STRINGS.ACCENT_COLOR}; + box-shadow: 0 0 2px 2px ${STRINGS.ACCENT_COLOR_DARK}; } } diff --git a/src/client/components/Input/FileInput.tsx b/src/client/components/Input/FileInput.tsx index c0abf36eb..5f439d7b1 100644 --- a/src/client/components/Input/FileInput.tsx +++ b/src/client/components/Input/FileInput.tsx @@ -5,6 +5,7 @@ import { InputProps } from './TextInput'; import { AuthContext } from '../../contexts/AuthContext'; import { useSignedUploadUrlMutation, useSignedReadUrlQuery } from '../../generated/graphql'; import STRINGS from '../../assets/strings.json'; +import Spinner from '../Loading/Spinner'; /** * Counter to allow for multiple FileInput elements to coexist on the same page. @@ -26,7 +27,7 @@ const FileLabelEl = styled.label` cursor: pointer; font-size: 1.2rem; padding: 0.6rem 2rem; - background: ${STRINGS.ACCENT_COLOR}; + background: ${STRINGS.ACCENT_COLOR_DARK}; width: fit-content; color: white; border-radius: 4px; @@ -38,8 +39,9 @@ const FileLabelEl = styled.label` &:hover, &:focus, &:active, + // pink glow input:focus + & { - box-shadow: 0px 0px 20px 0px rgba(0, 0, 255, 0.67); + box-shadow: 0px 0px 20px 0px rgba(255, 45, 85, 0.67); } `; @@ -72,6 +74,7 @@ export const FileInput: FC = props => { const [file, setFile] = useState(); const [getSignedUploadUrl] = useSignedUploadUrlMutation(); const [uploaded, setUploaded] = useState(false); + const [loading, toggleLoading] = useState(false); const { value, setState } = props; const [counter, setCounter] = useState(0); const fileReadUrlQuery = useSignedReadUrlQuery({ variables: { input: value } }); @@ -82,6 +85,7 @@ export const FileInput: FC = props => { if (!e.target.files) throw new Error('Files was null'); setFile(e.target.files[0]); setUploaded(false); + toggleLoading(true); }; useEffect(() => { @@ -96,6 +100,7 @@ export const FileInput: FC = props => { body: file, headers: { 'Content-Type': file.type, + 'x-goog-content-length-range': '0,5242880', }, method: 'PUT', }); @@ -105,8 +110,14 @@ export const FileInput: FC = props => { throw new Error(`Failed in upload to cloud storage: ${await res.text()}`); }) .catch(err => { - toast.error('File upload failed', { position: 'bottom-right' }); + const message = err.toString().includes('EntityTooLarge') + ? 'File larger than 5mb' + : 'File upload failed'; + toast.error(message, { position: 'bottom-right' }); throw new Error(err); + }) + .finally(() => { + toggleLoading(false); }); }, [file, getSignedUploadUrl, setState, user, uploaded]); @@ -126,11 +137,12 @@ export const FileInput: FC = props => { /> {/* eslint-disable-next-line react/jsx-one-expression-per-line */} - Upload {signedReadUrl ? 'new' : 'a'} resume + Upload {signedReadUrl ? 'new' : 'a'} résumé + {loading && } {signedReadUrl ? ( - View uploaded resume + View uploaded résumé ) : null} diff --git a/src/client/components/Input/SearchBox.tsx b/src/client/components/Input/SearchBox.tsx index 3baa8732a..892de2ad7 100644 --- a/src/client/components/Input/SearchBox.tsx +++ b/src/client/components/Input/SearchBox.tsx @@ -27,7 +27,8 @@ export const SearchBox = styled('input')` :focus, :active { outline: none; - border: 0.0625rem solid ${(props: Props) => (props.error ? '#FF647C' : STRINGS.ACCENT_COLOR)}; + border: 0.0625rem solid + ${(props: Props) => (props.error ? '#FF647C' : STRINGS.ACCENT_COLOR_DARK)}; } `; diff --git a/src/client/components/Input/Slider.tsx b/src/client/components/Input/Slider.tsx index 6d53d0253..9b61e6000 100644 --- a/src/client/components/Input/Slider.tsx +++ b/src/client/components/Input/Slider.tsx @@ -43,24 +43,24 @@ const SliderContainer = styled.div` } input:checked + label { - background-color: ${STRINGS.ACCENT_COLOR}; + background-color: ${STRINGS.ACCENT_COLOR_DARK}; color: #ffffff; /* border-color: #6979f8; */ z-index: 1; svg path { - fill: ${STRINGS.ACCENT_COLOR}; + fill: ${STRINGS.ACCENT_COLOR_DARK}; } } - input:not(:checked):focus + label { + input:not(:checked):focus-within + label { /* Color for keyboard users */ - box-shadow: inset 0 0 2px 2px ${STRINGS.ACCENT_COLOR}; + box-shadow: 0 0 2px 2px ${STRINGS.ACCENT_COLOR_DARK}; } - input:checked:focus + label { + input:checked:focus-within + label { /* Color for keyboard users */ - box-shadow: inset 0 0 2px 2px #ffffff; + box-shadow: 0 0 2px 2px #ffffff; } `; diff --git a/src/client/components/Input/TextArea.tsx b/src/client/components/Input/TextArea.tsx index 1abfe7628..ec63568e0 100644 --- a/src/client/components/Input/TextArea.tsx +++ b/src/client/components/Input/TextArea.tsx @@ -10,7 +10,7 @@ export const RawInput = styled.textarea` border: none; font-family: 'Roboto', sans-serif; font-size: ${({ fontSize = '1em' }: StyleProps): string => fontSize}; - color: ${STRINGS.DARK_TEXT_COLOR}; + color: ${STRINGS.LIGHT_TEXT_COLOR}; ::placeholder { color: ${STRINGS.LIGHT_TEXT_COLOR}; } diff --git a/src/client/components/Loading/Spinner.tsx b/src/client/components/Loading/Spinner.tsx index 5c525a7d9..44aa783ea 100644 --- a/src/client/components/Loading/Spinner.tsx +++ b/src/client/components/Loading/Spinner.tsx @@ -16,7 +16,7 @@ export const Wrapper = styled.div` & > div { width: 1rem; height: 1rem; - background-color: ${({ color }: StyleProps) => color || STRINGS.ACCENT_COLOR}; + background-color: ${({ color }: StyleProps) => color || STRINGS.ACCENT_COLOR_DARK}; border-radius: 100%; display: inline-block; diff --git a/src/client/components/Sidebar/Sidebar.tsx b/src/client/components/Sidebar/Sidebar.tsx index b7f220c73..8246a4016 100644 --- a/src/client/components/Sidebar/Sidebar.tsx +++ b/src/client/components/Sidebar/Sidebar.tsx @@ -1,7 +1,7 @@ import React, { useContext, FC, useCallback } from 'react'; import styled from 'styled-components'; import { NavLink as UglyNavLink } from 'react-router-dom'; -import SqLogo from '../../assets/img/VH_Pixel_Logo.png'; +import SqLogo from '../../assets/img/VH_Space_Logo_White.png'; import STRINGS from '../../assets/strings.json'; import NavButton from '../Buttons/NavButton'; import { SpaceBetweenColumn, FlexEndColumn } from '../Containers/FlexContainers'; diff --git a/src/client/components/Symbol/Checkmark.tsx b/src/client/components/Symbol/Checkmark.tsx index 139c1b432..b86caa905 100644 --- a/src/client/components/Symbol/Checkmark.tsx +++ b/src/client/components/Symbol/Checkmark.tsx @@ -22,7 +22,7 @@ export const Checkmark: FC = ({ width, height, value, color }: Props) => <> = ({ width, height, value, color }: Props) => )} diff --git a/src/client/components/Text/Announcement.tsx b/src/client/components/Text/Announcement.tsx index 565fd9d3b..dbf7b9db2 100644 --- a/src/client/components/Text/Announcement.tsx +++ b/src/client/components/Text/Announcement.tsx @@ -6,7 +6,7 @@ import Notification from '../../assets/img/notification.svg'; const Msg = styled.p` font-size: 1rem; - color: #ffffff; + color: ${STRINGS.DARK_TEXT_COLOR}; white-space: pre-line; grid-area: text; padding-left: 1.5rem; @@ -36,7 +36,7 @@ export const Announcement: FunctionComponent = (props: Props): JSX.Elemen borderRadius="1rem" width="35rem" backgroundOpacity="1" - backgroundColor={STRINGS.ACCENT_COLOR} + backgroundColor={STRINGS.ACCENT_COLOR_DARK} marginBottom="1rem" padding="1.5rem"> diff --git a/src/client/components/Text/Status.tsx b/src/client/components/Text/Status.tsx index 8b67cf8db..6bcf6fcf9 100644 --- a/src/client/components/Text/Status.tsx +++ b/src/client/components/Text/Status.tsx @@ -28,7 +28,7 @@ const StyledDiv = styled('div')` font-size: ${(props: StyledProps) => props.fontSize || '1rem'}; font-weight: ${(props: StyledProps) => props.fontWeight || 500}; color: ${(props: StyledProps) => props.fontColor || 'white'}; - background-color: ${(props: StyledProps) => props.backgroundColor || STRINGS.ACCENT_COLOR}; + background-color: ${(props: StyledProps) => props.backgroundColor || STRINGS.ACCENT_COLOR_DARK}; text-align: ${(props: StyledProps) => props.textAlign || 'center'}; border-radius: ${(props: StyledProps) => props.borderRadius || '8px'}; width: ${(props: StyledProps) => props.width || '5rem'}; diff --git a/src/client/routes/application/Application.tsx b/src/client/routes/application/Application.tsx index f68ba9409..74a98aefc 100644 --- a/src/client/routes/application/Application.tsx +++ b/src/client/routes/application/Application.tsx @@ -97,13 +97,21 @@ let autosaveTimeout: NodeJS.Timeout; * It should only be run on form submit because it is quite heavy. * @param input List of application inputs */ -const findRequiredUnfilled = (input: ApplicationInput[]): string => { +const findRequiredUnfilled = (input: ApplicationInput[]): JSX.Element => { const requiredQuestion = config .flatMap(section => section.fields as ConfigField[]) .find( - field => !field.optional && !input.find(el => el.question === field.fieldName && el.answer) + field => + !field.optional && !input.find(el => el.question === field.fieldName && el.answer.trim()) ); - return requiredQuestion ? `[${requiredQuestion.title}] is required` : ''; + return requiredQuestion ? ( +

+ {requiredQuestion.title} +  is required +

+ ) : ( + <> + ); }; export const Application: FunctionComponent = (): JSX.Element => { @@ -140,7 +148,7 @@ export const Application: FunctionComponent = (): JSX.Element => { onClick={async () => { const firstRequiredUnfilledToast = findRequiredUnfilled(input); toast.dismiss(); - if (firstRequiredUnfilledToast) + if (firstRequiredUnfilledToast !== <>) toast.error(firstRequiredUnfilledToast, { position: 'bottom-right', }); @@ -239,6 +247,7 @@ export const Application: FunctionComponent = (): JSX.Element => { {field.title ? ( {field.title} + {!field.optional ? `*` : null} {field.note ? {` - ${field.note}`} : null} ) : null} diff --git a/src/client/routes/dashboard/Frame.tsx b/src/client/routes/dashboard/Frame.tsx index 60fdd6fa9..fa7a0b177 100644 --- a/src/client/routes/dashboard/Frame.tsx +++ b/src/client/routes/dashboard/Frame.tsx @@ -27,6 +27,7 @@ const Layout = styled.div` height: 100vh; width: 100vw; display: grid; + background-color: #212529; grid: 'sidebar . . .' 1.5rem 'sidebar . header .' auto @@ -68,7 +69,7 @@ const Layout = styled.div` const Rectangle = styled.div` height: 0.4rem; width: 7.5rem; - background: ${STRINGS.ACCENT_COLOR}; + background: ${STRINGS.ACCENT_COLOR_DARK}; @media screen and (max-width: 456px) { display: none; @@ -86,7 +87,7 @@ const MenuIconButton = styled.button` & div { width: 35px; height: 5px; - background-color: ${STRINGS.ACCENT_COLOR}; + background-color: ${STRINGS.ACCENT_COLOR_DARK}; margin: 6px 0; } transform: scale(0.9); @@ -131,7 +132,7 @@ const Frame: FunctionComponent = (): JSX.Element => {
- + <Title style={{ color: '#FF647C' }} margin="1.5rem 0rem 0rem"> <Switch> {routes.map(route => { return route.authLevel.includes(currentUser.userType) ? ( diff --git a/src/client/routes/dashboard/HackerDash.tsx b/src/client/routes/dashboard/HackerDash.tsx index 86fb23e25..871b433ed 100644 --- a/src/client/routes/dashboard/HackerDash.tsx +++ b/src/client/routes/dashboard/HackerDash.tsx @@ -1,5 +1,6 @@ import React, { FunctionComponent, useState, useEffect, RefObject } from 'react'; import styled from 'styled-components'; +import { toast } from 'react-toastify'; import { Button } from '../../components/Buttons/Button'; import FloatingPopup from '../../components/Containers/FloatingPopup'; import { FlexColumn, FlexStartColumn } from '../../components/Containers/FlexContainers'; @@ -58,16 +59,16 @@ const statusConfig = { status: 'Submitted', statusBG: STRINGS.APPLICATION_COMPLETE_STATUSBG, statusColor: STRINGS.APPLICATION_COMPLETE_STATUSCOLOR, - text: "You may update your responses at any time by re-visiting the application.'", + text: 'You may update your responses at any time by re-visiting the application.', }, [ApplicationStatus.Confirmed]: { actions: [ { - action: () => void window.open('https://discord.gg/MbbfBWW', '_blank'), + action: () => void (window.location.href = '/api/auth/discord'), actionText: 'Join our Discord', }, ], - boldText: `Whoo hoo! We'll see you ${STRINGS.START_DAY}! Don't forget to join the Discord!`, + boldText: `Woohoo! We'll see you ${STRINGS.START_DAY}! Don't forget to join the Discord!`, img: applicationStatusSVG, status: 'Confirmed', statusBG: STRINGS.APPLICATION_COMPLETE_STATUSBG, @@ -116,8 +117,9 @@ const HackerDashBG = styled(FloatingPopup)` border-radius: 8px; height: min-content; width: 36rem; - background: rgba(247, 245, 249, 1); + background: ${STRINGS.BACKGROUND_DARK_SECONDARY}; padding: 1.5rem; + text-align: center; @media screen and (max-width: 456px) { width: 100%; @@ -133,6 +135,15 @@ const HackerDashBG = styled(FloatingPopup)` display: block; height: 200px; } + + #actions { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: inherit; + gap: 0.8rem; + } `; export const HackerDash: FunctionComponent = (): JSX.Element => { @@ -151,19 +162,36 @@ export const HackerDash: FunctionComponent = (): JSX.Element => { useEffect((): void => { statusConfig[ApplicationStatus.Accepted].actions[0].action = () => { - confirmMySpot() - .then(() => setShowConfetti(true)) - .catch(err => console.error(err)); + // eslint-disable-next-line no-alert + const confirmed = window.confirm('Are you sure you want to confirm your spot?'); + if (confirmed) { + confirmMySpot() + .then(() => setShowConfetti(true)) + .catch(err => console.error(err)); + } return undefined; }; statusConfig[ApplicationStatus.Accepted].actions[1].action = () => { - declineMySpot() - // no confetti :( - .catch(err => console.error(err)); + // eslint-disable-next-line no-alert + const confirmed = window.confirm('Are you sure you want to decline your spot?'); + if (confirmed) { + declineMySpot() + // no confetti :( + .catch(err => console.error(err)); + } return undefined; }; }, [confirmMySpot, declineMySpot]); + useEffect((): void => { + const msg = new URLSearchParams(window.location.search).get('msg'); + if (msg) { + toast.success(msg, { + position: 'bottom-right', + }); + } + }, []); + return ( <> <FlexStartColumn> @@ -176,7 +204,9 @@ export const HackerDash: FunctionComponent = (): JSX.Element => { ) : null} <HackerDashBG> <FlexColumn> - <Title fontSize="1.75rem">{STRINGS.HACKER_DASHBOARD_HEADER_TEXT} + + {STRINGS.HACKER_DASHBOARD_HEADER_TEXT} + {loading ? null : ( <> { )} - {statusInfo.actions.map(e => ( - - ))} +
+ {statusInfo.actions.map(e => ( + + ))} +
diff --git a/src/client/routes/dashboard/OrganizerDash.tsx b/src/client/routes/dashboard/OrganizerDash.tsx index c5845108c..19d64bf57 100644 --- a/src/client/routes/dashboard/OrganizerDash.tsx +++ b/src/client/routes/dashboard/OrganizerDash.tsx @@ -11,6 +11,13 @@ import { Button } from '../../components/Buttons/Button'; import { OverflowContainer } from '../../components/Containers/FlexContainers'; import 'chartjs-plugin-datalabels'; import STRINGS from '../../assets/strings.json'; +import { + useHackersQuery, + Gender, + ApplicationStatus, + ShirtSize, + HackersQuery, +} from '../../generated/graphql'; const Label = styled('span')` font-size: 1.25rem; @@ -49,6 +56,8 @@ const StyledFloatingPopupBottom = styled(FloatingPopup)` display: flex; `; +// Note: the following query is OUTDATED but supports the organizer dash stories as it stands. +// Need to update OrganizerDash to not use the mocked query. export const GET_STATISTICS = gql` query Statistics($number: Float!) { getAllHackerGenders { @@ -106,7 +115,7 @@ const STATUS_DEFAULT_CHART_OPTIONS: ChartOptions = { color: 'black', display: 'auto', font: { - size: 20, + size: 10, weight: 'bold', }, }, @@ -116,7 +125,7 @@ const STATUS_DEFAULT_CHART_OPTIONS: ChartOptions = { xAxes: [ { ticks: { - fontSize: 20, + fontSize: 10, }, }, ], @@ -124,7 +133,7 @@ const STATUS_DEFAULT_CHART_OPTIONS: ChartOptions = { showLines: true, title: { display: true, - fontSize: 24, + fontSize: 20, text: 'Number of Applicants', }, tooltips: { @@ -132,9 +141,25 @@ const STATUS_DEFAULT_CHART_OPTIONS: ChartOptions = { }, }; -const KVData = (data: { [key: string]: number }): ChartData => { - const keys = Object.keys(data).slice(0, -1); - const values = Object.values(data).slice(0, -1); +const NOT_FOUND = 'NOT FOUND'; +const KVData = (hackerData: string[], types: string): ChartData => { + let keys: string[] = []; + if (types === 'gender') { + keys = [...Object.values(Gender), 'NOT FOUND']; + } else if (types === 'status') { + keys = [...Object.values(ApplicationStatus), 'NOT FOUND']; + } else if (types === 'shirtSize') { + keys = [...Object.values(ShirtSize), 'NOT FOUND']; + } + + const values: number[] = new Array(keys.length).fill(0); + for (let type = 0; type < keys.length; type += 1) { + for (let i = 0; i < hackerData.length; i += 1) { + if (hackerData[i] === keys[type]) { + values[type] += 1; + } + } + } return { datasets: [ @@ -155,8 +180,8 @@ const pieChartOptions = (title: string): ChartOptions => ({ responsive: true, title: { display: true, - fontSize: 24, - position: 'bottom', + fontSize: 20, + position: 'left', text: title, }, }); @@ -190,13 +215,25 @@ export interface Props { disableAnimations?: boolean; } +function getGuaranteedHackerInfo( + data: HackersQuery | undefined, + property: 'status' | 'shirtSize' | 'gender' +): string[] { + return data + ? data.hackers.map(hacker => { + // need to assign hacker[property] to a variable for type checks + const hackerProperty = hacker[property]; + return typeof hackerProperty === 'string' ? hackerProperty : NOT_FOUND; + }) + : [NOT_FOUND]; +} + export const OrganizerDash: FC = ({ disableAnimations }): JSX.Element => { // TODO(leonm1/tangck): Fix queries to show real data. Should also clean up imports when done. // Currently the { loading: true } will stop this component from causing errors in prod. // const { loading, error, data } = { data: {} as any, error: 'Not Implemented', loading: true }; - const { loading, error, data } = useQuery(GET_STATISTICS, { - variables: { number: 5.0 }, - }); + + const { loading, error, data } = useHackersQuery(); if (loading) return ; if (error) { @@ -217,17 +254,26 @@ export const OrganizerDash: FC = ({ disableAnimations }): JSX.Element => - + - + {/* */} - - - + + ); diff --git a/src/client/routes/events/CheckInEvents.tsx b/src/client/routes/events/CheckInEvents.tsx index 58e56b94c..0e6a50f81 100644 --- a/src/client/routes/events/CheckInEvents.tsx +++ b/src/client/routes/events/CheckInEvents.tsx @@ -20,7 +20,7 @@ const HackerDashBG = styled(FloatingPopup)` border-radius: 8px; height: min-content; width: 36rem; - background: rgba(247, 245, 249, 1); + background: ${STRINGS.BACKGROUND_DARK_SECONDARY}; padding: 1.5rem; @media screen and (max-width: 456px) { diff --git a/src/client/routes/manage/ActionRenderer.stories.tsx b/src/client/routes/manage/ActionRenderer.stories.tsx index f11b001f7..5b9e12365 100644 --- a/src/client/routes/manage/ActionRenderer.stories.tsx +++ b/src/client/routes/manage/ActionRenderer.stories.tsx @@ -12,35 +12,35 @@ export default { export const Accepted: Story = args => ; Accepted.args = { - rowData: { id: '1', status: ApplicationStatus.Accepted }, + rowData: { id: '1', firstName: 'John', lastName: 'Doe', status: ApplicationStatus.Accepted }, }; export const Rejected: Story = args => ; Rejected.args = { - rowData: { id: '1', status: ApplicationStatus.Rejected }, + rowData: { id: '1', firstName: 'John', lastName: 'Doe', status: ApplicationStatus.Rejected }, }; export const Submitted: Story = args => ; Submitted.args = { - rowData: { id: '1', status: ApplicationStatus.Submitted }, + rowData: { id: '1', firstName: 'John', lastName: 'Doe', status: ApplicationStatus.Submitted }, }; export const Created: Story = args => ; Created.args = { - rowData: { id: '1', status: ApplicationStatus.Created }, + rowData: { id: '1', firstName: 'John', lastName: 'Doe', status: ApplicationStatus.Created }, }; export const Confirmed: Story = args => ; Confirmed.args = { - rowData: { id: '1', status: ApplicationStatus.Confirmed }, + rowData: { id: '1', firstName: 'John', lastName: 'Doe', status: ApplicationStatus.Confirmed }, }; export const Declined: Story = args => ; Declined.args = { - rowData: { id: '1', status: ApplicationStatus.Declined }, + rowData: { id: '1', firstName: 'John', lastName: 'Doe', status: ApplicationStatus.Declined }, }; export const Started: Story = args => ; Started.args = { - rowData: { id: '1', status: ApplicationStatus.Started }, + rowData: { id: '1', firstName: 'John', lastName: 'Doe', status: ApplicationStatus.Started }, }; diff --git a/src/client/routes/manage/ActionRenderer.tsx b/src/client/routes/manage/ActionRenderer.tsx index 1b8eed99e..d27feea6f 100644 --- a/src/client/routes/manage/ActionRenderer.tsx +++ b/src/client/routes/manage/ActionRenderer.tsx @@ -20,7 +20,7 @@ export type HackerStatusMutationFn = MutationFunction< >; export interface ActionRendererProps { - rowData: Pick; + rowData: Pick; } const Actions = styled('div')` display: flex; @@ -47,7 +47,7 @@ export function convertApplicationStatus(status: ApplicationStatus): string { export function createActionRenderer( updateStatus: (s: { status: ApplicationStatus; id: string }) => Promise ): FC { - return function ActionRenderer({ rowData: { id, status } }) { + return function ActionRenderer({ rowData: { id, firstName, lastName, status } }) { return ( {status && status !== ApplicationStatus.Created && status !== ApplicationStatus.Started ? ( @@ -55,6 +55,9 @@ export function createActionRenderer( option1="Accept" option2="Undecided" option3="Reject" + confirmMessageFunc={newState => + `Are you sure you want to set ${firstName} ${lastName} to '${newState}'?` + } value={convertApplicationStatus(status)} onChange={(input: string) => { const newStatus = processSliderInput(input); diff --git a/src/client/routes/manage/HackerTable.tsx b/src/client/routes/manage/HackerTable.tsx index e0563255f..22b44439e 100644 --- a/src/client/routes/manage/HackerTable.tsx +++ b/src/client/routes/manage/HackerTable.tsx @@ -77,18 +77,18 @@ const ColumnSelect = styled(Select)` outline: none; :focus, :active { - border: 0.0625rem solid ${STRINGS.ACCENT_COLOR}; + border: 0.0625rem solid ${STRINGS.ACCENT_COLOR_DARK}; } :hover:not(.select__control--is-focused) { border: 0.0625rem solid #ecebed; } :hover.select__control--is-focused { - border: 0.0625rem solid ${STRINGS.ACCENT_COLOR}; + border: 0.0625rem solid ${STRINGS.ACCENT_COLOR_DARK}; } } .select__control--is-focused, .select__control--is-selected { - border: 0.0625rem solid ${STRINGS.ACCENT_COLOR}; + border: 0.0625rem solid ${STRINGS.ACCENT_COLOR_DARK}; } .select__multi-value__label { font-size: 1rem; diff --git a/src/client/routes/manage/HackerTableRows.tsx b/src/client/routes/manage/HackerTableRows.tsx index 20d982bc2..49b79bdae 100644 --- a/src/client/routes/manage/HackerTableRows.tsx +++ b/src/client/routes/manage/HackerTableRows.tsx @@ -44,13 +44,15 @@ const StyledTable = styled(Table)` color: ${STRINGS.DARK_TEXT_COLOR}; } - .headerRow, - .evenRow, + .headerRow { + background-color: #ffffff; + } + .evenRow { + background-color: #ffffff; + } .oddRow { box-sizing: border-box; border-bottom: 0.0625rem solid #e0e0e0; - } - .oddRow { background-color: #fafafa; } @@ -113,10 +115,10 @@ const statusRenderer = ({ cellData }: TableCellProps): JSX.Element => { case ApplicationStatus.Rejected: return STRINGS.COLOR_PALETTE[6]; default: - return STRINGS.ACCENT_COLOR; + return STRINGS.ACCENT_COLOR_DARK; } }; - return ; + return ; }; const ResumeRenderer: FC = ({ rowData: { id } }) => ; diff --git a/src/client/routes/manage/HackerView.tsx b/src/client/routes/manage/HackerView.tsx index 50324a056..238f61a4b 100644 --- a/src/client/routes/manage/HackerView.tsx +++ b/src/client/routes/manage/HackerView.tsx @@ -30,7 +30,7 @@ const StyledTable = styled('table')` const HorizontalLine = styled.hr` margin: 0 2rem; - border: 0.0625rem solid ${STRINGS.ACCENT_COLOR}; + border: 0.0625rem solid ${STRINGS.ACCENT_COLOR_DARK}; margin-bottom: 0.25rem; `; @@ -142,7 +142,7 @@ export const HackerView: FC = props => { label={`${fieldTitle}:`} value={ signedReadUrl.length > 0 - ? `Resume Link` + ? `Résumé Link` : 'Not provided' } /> diff --git a/src/client/routes/manage/ResumeLink.tsx b/src/client/routes/manage/ResumeLink.tsx index ab85f4fdf..9adf79347 100644 --- a/src/client/routes/manage/ResumeLink.tsx +++ b/src/client/routes/manage/ResumeLink.tsx @@ -76,8 +76,8 @@ export const ResumeLink: FC = (props: { id: string }) => { const getLink = (): void => { setLinkLoc( signedReadUrl.length > 0 - ? `Resume Link` - : 'Resume not available' + ? `Résumé Link` + : 'Résumé not available' ); }; @@ -87,5 +87,5 @@ export const ResumeLink: FC = (props: { id: string }) => { // If an ID was provided, no error was thrown, and it's not loading, then we have a weird problem. if (!data) throw new Error('No error was thrown, but no data was found either :('); - return ; + return ; }; diff --git a/src/client/routes/manage/SliderInput.tsx b/src/client/routes/manage/SliderInput.tsx index e9ed11324..75fb1376a 100644 --- a/src/client/routes/manage/SliderInput.tsx +++ b/src/client/routes/manage/SliderInput.tsx @@ -57,6 +57,7 @@ export const SliderInput: FC = ({ option3="Reject" large value="Undecided" + confirmMessageFunc={newState => `Are you sure you want to set all hackers to '${newState}'?`} onChange={(input: string) => { const newStatus = processSliderInput(input); updateStatuses({ diff --git a/src/client/routes/manage/hackers.graphql.ts b/src/client/routes/manage/hackers.graphql.ts index 14b62ff83..ffbd64d53 100644 --- a/src/client/routes/manage/hackers.graphql.ts +++ b/src/client/routes/manage/hackers.graphql.ts @@ -44,6 +44,8 @@ export default gql` school status eventsAttended + gender + shirtSize } } diff --git a/src/client/routes/team/ViewTeam.tsx b/src/client/routes/team/ViewTeam.tsx index ff8c8962f..ecb0a01f6 100644 --- a/src/client/routes/team/ViewTeam.tsx +++ b/src/client/routes/team/ViewTeam.tsx @@ -13,7 +13,8 @@ interface ButtonProps { } const Status = styled.div` - background: ${({ background = 'rgba(255, 255, 255, 1)' }: ButtonProps): string => background}; + background: ${({ background = STRINGS.BACKGROUND_DARK_SECONDARY }: ButtonProps): string => + background}; padding: 1rem 2rem; margin-bottom: 1rem; `; @@ -30,7 +31,7 @@ export const ViewTeam: FC = ({ teamName }: Props): JSX.Element => { You have joined: - + {teamName} diff --git a/src/common/mockObjects.ts b/src/common/mockObjects.ts index 7686261c7..b0a33b8a5 100644 --- a/src/common/mockObjects.ts +++ b/src/common/mockObjects.ts @@ -94,7 +94,7 @@ export const MOCK_HACKER: Hacker = { userId, question: 'hackathonWaiver', answer: - 'I have read and agree to the VandyHacks VII Waiver', + 'I have read and agree to the VandyHacks VIII Waiver', }, { id: '21', diff --git a/src/server/auth/discord.ts b/src/server/auth/discord.ts new file mode 100644 index 000000000..db798e3b3 --- /dev/null +++ b/src/server/auth/discord.ts @@ -0,0 +1,113 @@ +import fetch from 'node-fetch'; +import { URLSearchParams } from 'url'; +import express from 'express'; +import { + ApplicationStatus, + UserType, + UserDbInterface, + HackerDbObject, +} from '../../client/generated/graphql'; + +const { + DISCORD_CALLBACK_URL, + DISCORD_CLIENT_ID, + DISCORD_CLIENT_SECRET, + DISCORD_BOT_TOKEN, + DISCORD_SERVER_ID, + DISCORD_VANDERBILT_ROLE, + DISCORD_HACKER_ROLE, + DISCORD_MENTOR_ROLE, + DISCORD_SPONSOR_ROLE, +} = process.env; + +function verify(req: express.Request): boolean { + // If we're not signed in, reject + const session = req.user as UserDbInterface; + if (!session) { + return false; + } + + // If the user is a hacker, we need to make sure + // they're confirmed (any other user type is good + // to go without confirmation) + if (session.userType === UserType.Hacker) { + const hackerSession = session as HackerDbObject; + return hackerSession.status === ApplicationStatus.Confirmed; + } + + return true; +} + +export function sendToDiscord(req: express.Request, res: express.Response): void { + if (!verify(req)) { + res.redirect('/'); + return; + } + + res.redirect( + `https://discord.com/api/oauth2/authorize?client_id=${DISCORD_CLIENT_ID}&redirect_uri=${encodeURIComponent( + `${req.protocol}://${req.get('host')}${DISCORD_CALLBACK_URL}` + )}&response_type=code&scope=guilds.join%20identify` + ); +} + +export async function discordCallback(req: express.Request, res: express.Response): Promise { + if (!verify(req)) { + res.send(401); + return; + } + + const failureHandler = (e: any): void => { + console.error(e); + res.redirect(`/?msg=${encodeURIComponent('Something broke on our end — try again later.')}`); + }; + + // Create params for OAuth and send request to get token + const params = new URLSearchParams(); + params.append('code', req.query.code); + params.append('client_id', DISCORD_CLIENT_ID); + params.append('client_secret', DISCORD_CLIENT_SECRET); + params.append('grant_type', 'authorization_code'); + params.append('redirect_uri', `${req.protocol}://${req.get('host')}${DISCORD_CALLBACK_URL}`); + const tokens = await fetch('https://discord.com/api/oauth2/token', { + method: 'POST', + body: params, + }) + .then(r => r.json()) + .catch(failureHandler); + + // Get user information (for ID) + const user = await fetch('https://discord.com/api/users/@me', { + method: 'GET', + headers: { Authorization: `Bearer ${tokens.access_token}` }, + }) + .then(r => r.json()) + .catch(failureHandler); + + const roles: { [K in string]: string } = { + SPONSOR: DISCORD_SPONSOR_ROLE as string, + MENTOR: DISCORD_MENTOR_ROLE as string, + HACKER: DISCORD_HACKER_ROLE as string, + }; + + const session = req.user as HackerDbObject; + const userObj = req.user as UserDbInterface; + + // Add user to Discord server + await fetch(`https://discord.com/api/guilds/${DISCORD_SERVER_ID}/members/${user.id}`, { + method: 'PUT', + body: JSON.stringify({ + access_token: tokens.access_token, + roles: [ + ...(session.school === 'Vanderbilt University' ? [DISCORD_VANDERBILT_ROLE] : []), + roles[userObj.userType], + ], + }), + headers: { + Authorization: `Bot ${DISCORD_BOT_TOKEN}`, + 'Content-Type': 'application/json', + }, + }).catch(failureHandler); + + res.redirect(`/?msg=${encodeURIComponent("Check your Discord — you've been added!")}`); +} diff --git a/src/server/index.ts b/src/server/index.ts index 6e8b7cb49..f10586b8d 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -14,10 +14,12 @@ import { StrategyNames, registerAuthRoutes } from './auth'; import { UnsubscribeHandler } from './mail/handlers'; import { UserDbInterface } from './generated/graphql'; import { pullCalendar } from './events'; +import { sendToDiscord, discordCallback } from './auth/discord'; import { serverPlugins, authPlugins } from './plugins'; -const { SESSION_SECRET, PORT, CALENDARID, NODE_ENV } = process.env; +const { SESSION_SECRET, PORT, CALENDARID, NODE_ENV, DISCORD_CALLBACK_URL } = process.env; + if (!SESSION_SECRET) throw new Error(`SESSION_SECRET not set`); if (!PORT) throw new Error(`PORT not set`); if (!CALENDARID) logger.info('CALENDARID not set; skipping ical integration'); @@ -45,8 +47,14 @@ export const schema = makeExecutableSchema({ (async () => { const dbClient = new DB(); const models = await dbClient.collections; - - app.use(helmet()); // sets good security defaults, see https://helmetjs.github.io/ + app.use( + helmet.contentSecurityPolicy({ + useDefaults: true, + directives: { + 'connect-src': ["'self'", 'https://*'], + }, + }) + ); // sets good security defaults, see https://helmetjs.github.io/ // Register auth functions app.use( @@ -118,6 +126,12 @@ export const schema = makeExecutableSchema({ res.send(calendar); }); + // Send user to Discord auth location + app.use('/api/auth/discord', sendToDiscord); + + // Callback for Discord Auth + app.use(DISCORD_CALLBACK_URL, discordCallback); + const db = (await dbClient.client).db('vaken'); const server = new ApolloServer({ diff --git a/src/server/mail/templates/accepted.ts b/src/server/mail/templates/accepted.ts index b4c7bfe08..1f44b63bb 100644 --- a/src/server/mail/templates/accepted.ts +++ b/src/server/mail/templates/accepted.ts @@ -263,7 +263,7 @@ export default (user: UserDbInterface): AWS.SES.SendEmailRequest => ({
- Congratulations! You’re invited to be a part of VandyHacks VII: Retro Edition! We enjoyed reading your application and would love to see your ideas come to life during our virtual event on October 2nd-4th! + Congratulations! You’re invited to be a part of VandyHacks VIII: Space Edition! We enjoyed reading your application and would love to see your ideas come to life during our virtual event on October 2nd-4th!
@@ -631,7 +631,7 @@ export default (user: UserDbInterface): AWS.SES.SendEmailRequest => ({ Text: { Charset: 'UTF-8', Data: `Hi ${escape(user.preferredName || user.firstName)}, - Congratulations! You’re invited to be a part of VandyHacks VII: Retro Edition! We enjoyed reading your application and would love to see your ideas come to life during our virtual event on October 2nd-4th! + Congratulations! You’re invited to be a part of VandyHacks VIII: Space Edition! We enjoyed reading your application and would love to see your ideas come to life during our virtual event on October 2nd-4th! Head over to the application portal here and confirm your attendance by October 2nd, 12:00 PM CDT. Make sure you’ve also read and checked “agree” to our hackathon waiver under the hacker application. diff --git a/src/server/mail/templates/confirmed.ts b/src/server/mail/templates/confirmed.ts index 7b3b275d1..4e26d03e0 100644 --- a/src/server/mail/templates/confirmed.ts +++ b/src/server/mail/templates/confirmed.ts @@ -263,7 +263,7 @@ export default (user: UserDbInterface): AWS.SES.SendEmailRequest => ({
- We're so excited that you'll be joining us for VandyHacks VII: Retro Edition! + We're so excited that you'll be joining us for VandyHacks VIII: Space Edition!
@@ -623,7 +623,7 @@ export default (user: UserDbInterface): AWS.SES.SendEmailRequest => ({ Text: { Charset: 'UTF-8', Data: `Hey ${escape(user.preferredName || user.firstName)}, - We're so excited that you'll be joining us for VandyHacks VII: Retro Edition! + We're so excited that you'll be joining us for VandyHacks VIII: Space Edition! This email is just to confirm that you've RSVPed to our event. We'll be in touch again soon with more information on our opening ceremony, but as a reminder, festivities will start at 7:00 PM CDT Friday, October 2nd, and wrap up by 4:00 PM CDT Sunday, October 4th. diff --git a/src/server/mail/templates/rejected.ts b/src/server/mail/templates/rejected.ts index 282608a15..a4276769b 100644 --- a/src/server/mail/templates/rejected.ts +++ b/src/server/mail/templates/rejected.ts @@ -263,7 +263,7 @@ export default (user: UserDbInterface): AWS.SES.SendEmailRequest => ({
- Thank you for your interest in VandyHacks VII: Retro Edition. Unfortunately, we are unable to offer you a spot at this year's event. + Thank you for your interest in VandyHacks VIII: Space Edition. Unfortunately, we are unable to offer you a spot at this year's event.
@@ -584,7 +584,7 @@ export default (user: UserDbInterface): AWS.SES.SendEmailRequest => ({ Text: { Charset: 'UTF-8', Data: `Hi ${escape(user.preferredName || user.firstName)}, - Thank you for your interest in VandyHacks VII: Retro Edition. Unfortunately, we are unable to offer you a spot at this year's event. + Thank you for your interest in VandyHacks VIII: Space Edition. Unfortunately, we are unable to offer you a spot at this year's event. We really appreciate your interest and hope you will apply to another VandyHacks opportunity in the future. Best, The VandyHacks Team`, diff --git a/src/server/mail/templates/submitted.ts b/src/server/mail/templates/submitted.ts index 6f8b9c2a3..d3f281c88 100644 --- a/src/server/mail/templates/submitted.ts +++ b/src/server/mail/templates/submitted.ts @@ -268,7 +268,7 @@ export default (user: UserDbInterface): AWS.SES.SendEmailRequest => ({
- Thanks for taking the time to complete your application! We’re so excited that you’re interested in being a part of VandyHacks VII: Retro Edition. + Thanks for taking the time to complete your application! We’re so excited that you’re interested in being a part of VandyHacks VIII: Space Edition.
@@ -454,7 +454,7 @@ export default (user: UserDbInterface): AWS.SES.SendEmailRequest => ({
You are receiving this application update because you applied at apply.vandyhacks.org. If you would like to opt-out of - any future emails pertaining to VandyHacks VII: Retro Edition applications, please click here
@@ -595,7 +595,7 @@ export default (user: UserDbInterface): AWS.SES.SendEmailRequest => ({ Charset: 'UTF-8', Data: `Thank you for applying! Hi ${escape(user.preferredName || user.firstName)}, - Thanks for taking the time to complete your application! We’re so excited that you’re interested in being a part of VandyHacks VII: Retro Edition. + Thanks for taking the time to complete your application! We’re so excited that you’re interested in being a part of VandyHacks VIII: Space Edition. We will be reviewing your submission soon, so be on the lookout for another email regarding your status. Until then, stay hyped about VandyHacks! Like our page on Facebook and follow us on Instagram. Cheers, diff --git a/src/server/storage/gcp.ts b/src/server/storage/gcp.ts index 98fe5a858..70e556c58 100644 --- a/src/server/storage/gcp.ts +++ b/src/server/storage/gcp.ts @@ -25,6 +25,9 @@ export const getSignedUploadUrl = async (filename: string): Promise => { contentType: 'application/pdf', expires: Date.now() + 15 * 60 * 1000, // 15 minutes version: 'v4' as const, + extensionHeaders: { + 'x-goog-content-length-range': '0,5242880', + }, }; const [url] = await storage.bucket(BUCKET_NAME).file(filename).getSignedUrl(options);