diff --git a/Dockerfile b/Dockerfile index c9b3a48..add3992 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-buster +FROM node:18 WORKDIR /opt/app @@ -11,6 +11,8 @@ RUN npm install COPY . . +RUN npx prisma generate + RUN npm run build RUN chown node:node /opt/app/ diff --git a/package-lock.json b/package-lock.json index 8b2e5e8..2be5b6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,32 +9,32 @@ "version": "0.0.1", "license": "GPL-3.0-or-later", "dependencies": { - "@discordjs/builders": "^1.2.0", + "@discordjs/builders": "^1.3.0", "@prisma/client": "^4.0.0", "@sapphire/discord.js-utilities": "^5.0.0", - "@sapphire/framework": "^3.1.1", + "@sapphire/framework": "^3.1.3", "@sapphire/plugin-scheduled-tasks": "^4.0.0", "@sapphire/plugin-subcommands": "^3.0.0", "@sapphire/stopwatch": "^1.4.1", - "@sapphire/ts-config": "^3.3.4", "@sapphire/utilities": "^3.9.2", "@types/node": "^18.0.3", "bullmq": "^1.89.1", "discord-api-types": "^0.33.3", - "discord.js": "^13.10.3", + "discord.js": "^13.12.0", "dotenv": "^16.0.1", - "prisma": "^4.2.1", "ts-node": "^10.8.2", "typescript": "^4.7.4" }, "devDependencies": { + "@sapphire/ts-config": "^3.3.4", "@types/ioredis": "^4.28.10", "@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/parser": "^5.30.7", "eslint": "8.22.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.0.0", - "eslint-plugin-import": "^2.26.0" + "eslint-plugin-import": "^2.26.0", + "prisma": "^4.4.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -49,12 +49,13 @@ } }, "node_modules/@discordjs/builders": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.2.0.tgz", - "integrity": "sha512-ARy4BUTMU+S0ZI6605NDqfWO+qZqV2d/xfY32z3hVSsd9IaAKJBZ1ILTZLy87oIjW8+gUpQmk9Kt0ZP9bmmd8Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.3.0.tgz", + "integrity": "sha512-Pvca6Nw8Hp+n3N+Wp17xjygXmMvggbh5ywUsOYE2Et4xkwwVRwgzxDJiMUuYapPtnYt4w/8aKlf5khc8ipLvhg==", "dependencies": { - "@sapphire/shapeshift": "^3.5.1", - "discord-api-types": "^0.37.3", + "@discordjs/util": "^0.1.0", + "@sapphire/shapeshift": "^3.7.0", + "discord-api-types": "^0.37.12", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.1", "tslib": "^2.4.0" @@ -64,22 +65,30 @@ } }, "node_modules/@discordjs/builders/node_modules/discord-api-types": { - "version": "0.37.8", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.8.tgz", - "integrity": "sha512-uhol9KQ2moExZItMpuDMkf0R7sqqNHqcJBFN7S5iSdXBVCMRO7sC0GoyuRrv6ZDBYxoFU6nDy4dv0nld/aysqA==" + "version": "0.37.14", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.14.tgz", + "integrity": "sha512-byBH7SfDCMJwxdqeS8k5sihltH88/YPhuwx+vF2cftSxFLdxyHyU/ZxDL3bq+LB2c4ls/TymE76/ISlLfniUXg==" }, "node_modules/@discordjs/collection": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.1.0.tgz", - "integrity": "sha512-PQ2Bv6pnT7aGPCKWbvvNRww5tYCGpggIQVgpuF9TdDPeR6n6vQYxezXiLVOS9z2B62Dp4c+qepQ15SgJbLYtCQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.2.0.tgz", + "integrity": "sha512-VvrrtGb7vbfPHzbhGq9qZB5o8FOB+kfazrxdt0OtxzSkoBuw9dURMkCwWizZ00+rDpiK2HmLHBZX+y6JsG9khw==", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/util": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.1.0.tgz", + "integrity": "sha512-e7d+PaTLVQav6rOc2tojh2y6FE8S7REkqLldq1XF4soCx74XB/DIjbVbVLtBemf0nLW77ntz0v+o5DytKwFNLQ==", "engines": { "node": ">=16.9.0" } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -100,9 +109,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", + "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -113,11 +122,14 @@ "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "engines": { + "node": ">=12.22" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/nzakas" @@ -264,12 +276,12 @@ } }, "node_modules/@prisma/client": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.3.1.tgz", - "integrity": "sha512-FA0/d1VMJNWqzU7WVWTNWJ+lGOLR9JUBnF73GdIPAEVo/6dWk4gHx0EmgeU+SMv4MZoxgOeTBJF2azhg7x0hMw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.5.0.tgz", + "integrity": "sha512-B2cV0OPI1smhdYUxsJoLYQLoMlLH06MUxgFUWQnHodGMX98VRVXKmQE/9OcrTNkqtke5RC+YU24Szxd04tZA2g==", "hasInstallScript": true, "dependencies": { - "@prisma/engines-version": "4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b" + "@prisma/engines-version": "4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452" }, "engines": { "node": ">=14.17" @@ -284,15 +296,16 @@ } }, "node_modules/@prisma/engines": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.3.1.tgz", - "integrity": "sha512-4JF/uMaEDAPdcdZNOrnzE3BvrbGpjgV0FcPT3EVoi6I86fWkloqqxBt+KcK/+fIRR0Pxj66uGR9wVH8U1Y13JA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.5.0.tgz", + "integrity": "sha512-4t9ir2SbQQr/wMCNU4YpHWp5hU14J2m3wHUZnGJPpmBF8YtkisxyVyQsKd1e6FyLTaGq8LOLhm6VLYHKqKNm+g==", + "devOptional": true, "hasInstallScript": true }, "node_modules/@prisma/engines-version": { - "version": "4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b.tgz", - "integrity": "sha512-8yWpXkQRmiSfsi2Wb/ZS5D3RFbeu/btL9Pm/gdF4phB0Lo5KGsDFMxFMgaD64mwED2nHc8ZaEJg/+4Jymb9Znw==" + "version": "4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452.tgz", + "integrity": "sha512-o7LyVx8PPJBLrEzLl6lpxxk2D5VnlM4Fwmrbq0NoT6pr5aa1OuHD9ZG+WJY6TlR/iD9bhmo2LNcxddCMr5Rv2A==" }, "node_modules/@sapphire/async-queue": { "version": "1.5.0", @@ -313,13 +326,13 @@ } }, "node_modules/@sapphire/discord.js-utilities": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-5.0.0.tgz", - "integrity": "sha512-XvXkL0/e4AwKIipSxPeNNa8UPmSCoc+vwkNrnvV43a0JUJ1acxPPWrcpxAzE9lRxPY/vDLYaaEw7M/hkg3i5xQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-5.1.1.tgz", + "integrity": "sha512-xWiduo2kYXMJ2IHKYjPGzL6VisTP/kwVh61BlxBbnPOKQ87F3EYe4WuXuX7JqoPUZVdRSG3ZuBgrz0mKGF4p3w==", "dependencies": { "@sapphire/discord-utilities": "^2.11.6", - "@sapphire/time-utilities": "^1.7.6", - "@sapphire/utilities": "^3.9.2", + "@sapphire/duration": "^1.0.0", + "@sapphire/utilities": "^3.11.0", "tslib": "^2.4.0" }, "engines": { @@ -327,22 +340,29 @@ "npm": ">=7.0.0" } }, + "node_modules/@sapphire/duration": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/duration/-/duration-1.0.0.tgz", + "integrity": "sha512-B+6nKYnBmIlqqbamcR4iBvbQHz6/Kq2JUVM0rA3lQ+aYUYDdcA1Spt66CKtPWwdTYEtSv0VY6Jv27WCtFNYTUg==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/@sapphire/framework": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.1.1.tgz", - "integrity": "sha512-dWWIhqFwVZ7nMJ6o7mIhgOAQhSfaue6IPyRSYhXuLEOU9uiQpLioXaYckVAVspRGAc5MqIalOV2htjQF2nCgjw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.1.3.tgz", + "integrity": "sha512-YHB6oeY095vrRv8ksW0zm/GSWuw+vDLvU0BzJBTGI0KYQfNq2d6OVCjY0ADxFgQSgC9AxOHj2h2GvGcLET+S4g==", "dependencies": { "@discordjs/builders": "^0.16.0", "@sapphire/discord-utilities": "^2.11.6", - "@sapphire/discord.js-utilities": "^5.0.0", - "@sapphire/lexure": "^1.0.2", - "@sapphire/pieces": "^3.5.1", - "@sapphire/ratelimits": "^2.4.4", - "@sapphire/result": "^2.4.1", - "@sapphire/stopwatch": "^1.4.1", - "@sapphire/utilities": "^3.9.3", - "@types/object-hash": "^2.2.1", - "object-hash": "^3.0.0", + "@sapphire/discord.js-utilities": "^5.0.1", + "@sapphire/lexure": "^1.1.1", + "@sapphire/pieces": "^3.5.2", + "@sapphire/ratelimits": "^2.4.5", + "@sapphire/result": "^2.5.0", + "@sapphire/stopwatch": "^1.5.0", + "@sapphire/utilities": "^3.10.0", "tslib": "^2.4.0" }, "engines": { @@ -372,11 +392,11 @@ "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" }, "node_modules/@sapphire/lexure": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.0.2.tgz", - "integrity": "sha512-KKKcCvjkB6AImGzpWdrbLVI++VnRinpus+a4yu+PUT7zUlzUZdma1P/P8XlRDFEx6U+d5jk8ygKyTPzQKvkqRA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.1.2.tgz", + "integrity": "sha512-+v3P3EMDdFoybHH7c7cMcz30jEyxujkxWu5f958cf/Sm27fMM0IqwILnNFUpExZCBAueEM/eoSgbRl4q+K+0jg==", "dependencies": { - "@sapphire/result": "^2.4.1" + "@sapphire/result": "^2.6.0" }, "engines": { "node": ">=v14.0.0", @@ -384,12 +404,12 @@ } }, "node_modules/@sapphire/pieces": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.1.tgz", - "integrity": "sha512-GEm7W6hAMC1yN76z0SZlIij66MDcuvWf7ra2TPGhflmv5ZUG4vNHNMktexP4AwEgKeF1jKJouVrIs3lAC3e4ZQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.2.tgz", + "integrity": "sha512-B8ghwre5naTIMnJIlqJGhKX6ZTpGqz4oAtBd/ihX0CY69cPtbem3VHfZ8Sf5C+50l3mfe2AU7CfZQn9kLQR2fQ==", "dependencies": { - "@discordjs/collection": "^1.0.1", - "@sapphire/utilities": "^3.9.2", + "@discordjs/collection": "^1.1.0", + "@sapphire/utilities": "^3.10.0", "tslib": "^2.4.0" }, "engines": { @@ -398,11 +418,12 @@ } }, "node_modules/@sapphire/plugin-scheduled-tasks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.0.tgz", - "integrity": "sha512-MIYiG40HW9kPeZGPcGlLX3uPkKaruG2GIkUhu5gNS1kJogtx6NdZlY5hKBDnpjl1jND5+d2gX9aaLNFA7+UxKA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.1.tgz", + "integrity": "sha512-vLxfHBu2vKaJZ9v2f4z+VDZaPeDqS8bm+Sc2minRwJPw1hWAHiPqmxCBPIONY7eOQ9qKayvhKYTIwwruxgO/Mg==", "dependencies": { - "@sapphire/time-utilities": "^1.7.6", + "@sapphire/stopwatch": "^1.4.1", + "@sapphire/utilities": "^3.9.3", "tslib": "^2.4.0" }, "engines": { @@ -411,11 +432,11 @@ } }, "node_modules/@sapphire/plugin-subcommands": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@sapphire/plugin-subcommands/-/plugin-subcommands-3.2.1.tgz", - "integrity": "sha512-I+NmbewS85oEfFx/0t8cGtimLmNGMzF6k5eigUmRakb7t6m1EK54cvWwV3zFbkhCMWI6e+ObiIe5XJVel8oWqg==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-subcommands/-/plugin-subcommands-3.2.3.tgz", + "integrity": "sha512-xUDkHdOXmqquO++I54ZOZg8Prh2YIJ7sSGBLXCU+FiNDbsfzbxr/McCfnKL65L6RBYOjf8d06up3GKPL8t9GpQ==", "dependencies": { - "@sapphire/utilities": "^3.9.2", + "@sapphire/utilities": "^3.11.0", "tslib": "^2.4.0" }, "engines": { @@ -424,11 +445,11 @@ } }, "node_modules/@sapphire/ratelimits": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@sapphire/ratelimits/-/ratelimits-2.4.4.tgz", - "integrity": "sha512-9gZ1BaY99HLWOcfuhlu0WklirHhVc6QD1pm5/v2W0O9pBpMHrd1GImVMXjYZRoy1qpmE2ZggSmN1665lktTCMw==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@sapphire/ratelimits/-/ratelimits-2.4.5.tgz", + "integrity": "sha512-2wqpVPRaPUE+CWStLm6wGLj1uA4Ln/9qbH4Ue/eCHC6/R5lJz0+8nGD1LpiYOcyeVLTHbmwODGeD92obkPej2g==", "dependencies": { - "@sapphire/time-utilities": "^1.7.4" + "@sapphire/timer-manager": "^1.0.0" }, "engines": { "node": ">=v14.0.0", @@ -436,18 +457,18 @@ } }, "node_modules/@sapphire/result": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.4.1.tgz", - "integrity": "sha512-RWgp+cCm1dhE/voMGwp3z5xGmsOluXW9EPIXyO+khMXxZDL3iAgp4/ZCSFEw3nI98njwGmgWYIzdQfCu3WA4OA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.6.0.tgz", + "integrity": "sha512-gdW6n/oDZ8aC1439Ub3RiLQ6L4VHAxbN0AhGJWNkEZ6Z6Ww2V62fwRiA/73OPfgYQKXk9ljhAFiqNO91KAonHQ==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, "node_modules/@sapphire/shapeshift": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.6.0.tgz", - "integrity": "sha512-tu2WLRdo5wotHRvsCkspg3qMiP6ETC3Q1dns1Q5V6zKUki+1itq6AbhMwohF9ZcLoYqg+Y8LkgRRtVxxTQVTBQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.7.0.tgz", + "integrity": "sha512-A6vI1zJoxhjWo4grsxpBRBgk96SqSdjLX5WlzKp9H+bJbkM07mvwcbtbVAmUZHbi/OG3HLfiZ1rlw4BhH6tsBQ==", "dependencies": { "fast-deep-equal": "^3.1.3", "lodash.uniqwith": "^4.5.0" @@ -458,24 +479,21 @@ } }, "node_modules/@sapphire/stopwatch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@sapphire/stopwatch/-/stopwatch-1.4.1.tgz", - "integrity": "sha512-FoZIM7oQ1kwkjWpl/rKReuDFSlkCDjDp//1Np2mmQD+xQ2Zyo/J2MaYAITprwQr3AUBu/OOUJvqm7f8lA9R7gA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/stopwatch/-/stopwatch-1.5.0.tgz", + "integrity": "sha512-DtyKugdy3JTqm6JnEepTY64fGJAqlusDVrlrzifEgSCfGYCqpvB+SBldkWtDH+z+zLcp+PyaFLq7xpVfkhmvGg==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.4.0" }, "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, - "node_modules/@sapphire/time-utilities": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@sapphire/time-utilities/-/time-utilities-1.7.6.tgz", - "integrity": "sha512-VsMVYFmS9Iu0buPs7gwn1D6vqIC04ezVMBRIo8vRTB2s7UNN/vQReX2cLABFoDVqs7RHQsvr2DPoTWHEDYw9YA==", - "dependencies": { - "@sapphire/utilities": "^3.9.2" - }, + "node_modules/@sapphire/timer-manager": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/timer-manager/-/timer-manager-1.0.0.tgz", + "integrity": "sha512-vxxnv75QPMGKt6IB6nL2xRJfwzcUQ9DBGzJLg6G8eS5O4u7j3IR/yr/GQsa4gIpjw6kQOgn8lUdnSTlpnERTbQ==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" @@ -485,6 +503,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/@sapphire/ts-config/-/ts-config-3.3.4.tgz", "integrity": "sha512-mWEUxCXh3cHKI7C8HJ049exVTMNaq+A/lJEDfM5ENSQ/OOZHd5DdmXn2jrYqFWbTRCHa0Vp2FAmACWBwePsBtg==", + "dev": true, "dependencies": { "tslib": "^2.3.1", "typescript": "^4.6.3" @@ -495,9 +514,9 @@ } }, "node_modules/@sapphire/utilities": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.9.3.tgz", - "integrity": "sha512-7+ZjfbmRHqewmH32jpZfzrEuHpvTttTG7WjDl1GUtc4pkOMr0kYybrZmIEZYsUvF7PWzO0GrmOK2zWs3GuJo7g==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.11.0.tgz", + "integrity": "sha512-ich7J+329UTEgWxgk8b871rMhbFW/hvXdabdiKaUKd6g10eIMkIakWf+EGkDQsiDSiebIXll9TIPPmWtN3cVSw==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" @@ -545,9 +564,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.7.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz", - "integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==" + "version": "18.11.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz", + "integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==" }, "node_modules/@types/node-fetch": { "version": "2.6.2", @@ -571,10 +590,11 @@ "node": ">= 6" } }, - "node_modules/@types/object-hash": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-2.2.1.tgz", - "integrity": "sha512-i/rtaJFCsPljrZvP/akBqEwUP2y5cZLOmvO+JaYnz01aPknrQ+hB5MRcO7iqCUsFaYfTG8kGfKUyboA07xeDHQ==" + "node_modules/@types/semver": { + "version": "7.3.12", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz", + "integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==", + "dev": true }, "node_modules/@types/ws": { "version": "8.5.3", @@ -585,16 +605,15 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.2.tgz", - "integrity": "sha512-OwwR8LRwSnI98tdc2z7mJYgY60gf7I9ZfGjN5EjCwwns9bdTuQfAXcsjSB2wSQ/TVNYSGKf4kzVXbNGaZvwiXw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.1.tgz", + "integrity": "sha512-FsWboKkWdytGiXT5O1/R9j37YgcjO8MKHSUmWnIEjVaz0krHkplPnYi7mwdb+5+cs0toFNQb0HIrN7zONdIEWg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/type-utils": "5.36.2", - "@typescript-eslint/utils": "5.36.2", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/type-utils": "5.40.1", + "@typescript-eslint/utils": "5.40.1", "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", "regexpp": "^3.2.0", "semver": "^7.3.7", @@ -618,14 +637,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.36.2.tgz", - "integrity": "sha512-qS/Kb0yzy8sR0idFspI9Z6+t7mqk/oRjnAYfewG+VN73opAUvmYL3oPIMmgOX6CnQS6gmVIXGshlb5RY/R22pA==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.1.tgz", + "integrity": "sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/typescript-estree": "5.40.1", "debug": "^4.3.4" }, "engines": { @@ -645,13 +664,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.36.2.tgz", - "integrity": "sha512-cNNP51L8SkIFSfce8B1NSUBTJTu2Ts4nWeWbFrdaqjmn9yKrAaJUBHkyTZc0cL06OFHpb+JZq5AUHROS398Orw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.1.tgz", + "integrity": "sha512-jkn4xsJiUQucI16OLCXrLRXDZ3afKhOIqXs4R3O+M00hdQLKR58WuyXPZZjhKLFCEP2g+TXdBRtLQ33UfAdRUg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2" + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/visitor-keys": "5.40.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -662,13 +681,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.36.2.tgz", - "integrity": "sha512-rPQtS5rfijUWLouhy6UmyNquKDPhQjKsaKH0WnY6hl/07lasj8gPaH2UD8xWkePn6SC+jW2i9c2DZVDnL+Dokw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.1.tgz", + "integrity": "sha512-DLAs+AHQOe6n5LRraXiv27IYPhleF0ldEmx6yBqBgBLaNRKTkffhV1RPsjoJBhVup2zHxfaRtan8/YRBgYhU9Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.36.2", - "@typescript-eslint/utils": "5.36.2", + "@typescript-eslint/typescript-estree": "5.40.1", + "@typescript-eslint/utils": "5.40.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -689,9 +708,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.2.tgz", - "integrity": "sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.1.tgz", + "integrity": "sha512-Icg9kiuVJSwdzSQvtdGspOlWNjVDnF3qVIKXdJ103o36yRprdl3Ge5cABQx+csx960nuMF21v8qvO31v9t3OHw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -702,13 +721,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.2.tgz", - "integrity": "sha512-8fyH+RfbKc0mTspfuEjlfqA4YywcwQK2Amcf6TDOwaRLg7Vwdu4bZzyvBZp4bjt1RRjQ5MDnOZahxMrt2l5v9w==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.1.tgz", + "integrity": "sha512-5QTP/nW5+60jBcEPfXy/EZL01qrl9GZtbgDZtDPlfW5zj/zjNrdI2B5zMUHmOsfvOr2cWqwVdWjobCiHcedmQA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/visitor-keys": "5.40.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -729,17 +748,19 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.36.2.tgz", - "integrity": "sha512-uNcopWonEITX96v9pefk9DC1bWMdkweeSsewJ6GeC7L6j2t0SJywisgkr9wUTtXk90fi2Eljj90HSHm3OGdGRg==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.1.tgz", + "integrity": "sha512-a2TAVScoX9fjryNrW6BZRnreDUszxqm9eQ9Esv8n5nXApMW0zeANUYlwh/DED04SC/ifuBvXgZpIK5xeJHQ3aw==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/typescript-estree": "5.40.1", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -753,12 +774,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.2.tgz", - "integrity": "sha512-BtRvSR6dEdrNt7Net2/XDjbYKU5Ml6GqJgVfXT0CxTCJlnIqK7rAGreuWKMT2t8cFUT2Msv5oxw0GMRD7T5J7A==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.1.tgz", + "integrity": "sha512-A2DGmeZ+FMja0geX5rww+DpvILpwo1OsiQs0M+joPWJYsiEFBLsH0y1oFymPNul6Z5okSmHpP4ivkc2N0Cgfkw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.36.2", + "@typescript-eslint/types": "5.40.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -927,9 +948,9 @@ } }, "node_modules/bullmq": { - "version": "1.90.1", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.90.1.tgz", - "integrity": "sha512-JY8mNzfnl+lfzFFzLJa6if+4YFvCMuJZDtQ8gvkcedoet+fDPEETF0iZ2fuzxCizuneARCniAiwIR/ESnqbuKw==", + "version": "1.91.1", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.91.1.tgz", + "integrity": "sha512-u7dat9I8ZwouZ651AMZkBSvB6NVUPpnAjd4iokd9DM41whqIBnDjuL11h7+kEjcpiDKj6E+wxZiER00FqirZQg==", "dependencies": { "cron-parser": "^4.6.0", "get-port": "6.1.2", @@ -939,7 +960,7 @@ "msgpackr": "^1.6.2", "semver": "^7.3.7", "tslib": "^2.0.0", - "uuid": "^8.3.2" + "uuid": "^9.0.0" } }, "node_modules/call-bind": { @@ -981,9 +1002,9 @@ } }, "node_modules/cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==", "engines": { "node": ">=0.10.0" } @@ -1139,19 +1160,19 @@ "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg==" }, "node_modules/discord.js": { - "version": "13.10.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.3.tgz", - "integrity": "sha512-cIARuxfpQDeqA9Zw3fz4IL20xAhtMsjwJIf7/K82R3n2xROG9/fAx+7qjX8ysp9BfflYqMu2ZskyWq1EAmL5BA==", + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.12.0.tgz", + "integrity": "sha512-K5qhREsYcTHkEqt7+7LcSoXTeQYZpI+SQRs9ei/FhbhUpirmjqFtN99P8W2mrKUyhhy7WXWm7rnna0AooKtIpw==", "dependencies": { "@discordjs/builders": "^0.16.0", "@discordjs/collection": "^0.7.0", "@sapphire/async-queue": "^1.5.0", "@types/node-fetch": "^2.6.2", "@types/ws": "^8.5.3", - "discord-api-types": "^0.33.3", + "discord-api-types": "^0.33.5", "form-data": "^4.0.0", "node-fetch": "^2.6.7", - "ws": "^8.8.1" + "ws": "^8.9.0" }, "engines": { "node": ">=16.6.0", @@ -1201,30 +1222,30 @@ } }, "node_modules/dotenv": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz", - "integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", "engines": { "node": ">=12" } }, "node_modules/es-abstract": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", - "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.2", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -1234,6 +1255,7 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -1284,14 +1306,14 @@ } }, "node_modules/eslint": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz", - "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", + "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.10.5", + "@humanwhocodes/module-importer": "^1.0.1", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1301,13 +1323,12 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", "globby": "^11.1.0", @@ -1316,6 +1337,7 @@ "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -1326,8 +1348,7 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" @@ -1635,9 +1656,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1784,12 +1805,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -1800,9 +1815,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, "dependencies": { "function-bind": "^1.1.1", @@ -2113,9 +2128,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "engines": { "node": ">= 0.4" @@ -2125,9 +2140,9 @@ } }, "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -2284,6 +2299,12 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/js-sdsl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2386,9 +2407,9 @@ } }, "node_modules/luxon": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.3.tgz", - "integrity": "sha512-+EfHWnF+UT7GgTnq5zXg3ldnTKL2zdv7QJgsU5bjjpbH17E3qi/puMhQyJVYuCq+FRkogvB5WB6iVvUr+E4a7w==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", + "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==", "engines": { "node": ">=12" } @@ -2452,10 +2473,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/ms": { "version": "2.1.2", @@ -2463,11 +2487,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/msgpackr": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.6.2.tgz", - "integrity": "sha512-bqSQ0DYJbXbrJcrZFmMygUZmqQiDfI2ewFVWcrZY12w5XHWtPuW4WppDT/e63Uu311ajwkRRXSoF0uILroBeTA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.7.2.tgz", + "integrity": "sha512-mWScyHTtG6TjivXX9vfIy2nBtRupaiAj0HQ2mtmpmYujAmqZmaaEVPaSZ1NKLMvicaMLFzEaMk0ManxMRg8rMQ==", "optionalDependencies": { - "msgpackr-extract": "^2.0.2" + "msgpackr-extract": "^2.1.2" } }, "node_modules/msgpackr-extract": { @@ -2527,14 +2551,6 @@ "node-gyp-build-optional-packages-test": "build-test.js" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -2733,12 +2749,13 @@ } }, "node_modules/prisma": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.3.1.tgz", - "integrity": "sha512-90xo06wtqil76Xsi3mNpc4Js3SdDRR5g4qb9h+4VWY4Y8iImJY6xc3PX+C9xxTSt1lr0Q89A0MLkJjd8ax6KiQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.5.0.tgz", + "integrity": "sha512-9Aeg4qiKlv9Wsjz4NO8k2CzRzlvS3A4FYVJ5+28sBBZ0eEwbiVOE/Jj7v6rZC1tFW2s4GSICQOAyuOjc6WsNew==", + "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "4.3.1" + "@prisma/engines": "4.5.0" }, "bin": { "prisma": "build/index.js", @@ -2919,10 +2936,24 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3200,9 +3231,9 @@ } }, "node_modules/typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3236,19 +3267,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "bin": { "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -3314,9 +3339,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", "engines": { "node": ">=10.0.0" }, @@ -3369,33 +3394,39 @@ } }, "@discordjs/builders": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.2.0.tgz", - "integrity": "sha512-ARy4BUTMU+S0ZI6605NDqfWO+qZqV2d/xfY32z3hVSsd9IaAKJBZ1ILTZLy87oIjW8+gUpQmk9Kt0ZP9bmmd8Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.3.0.tgz", + "integrity": "sha512-Pvca6Nw8Hp+n3N+Wp17xjygXmMvggbh5ywUsOYE2Et4xkwwVRwgzxDJiMUuYapPtnYt4w/8aKlf5khc8ipLvhg==", "requires": { - "@sapphire/shapeshift": "^3.5.1", - "discord-api-types": "^0.37.3", + "@discordjs/util": "^0.1.0", + "@sapphire/shapeshift": "^3.7.0", + "discord-api-types": "^0.37.12", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.1", "tslib": "^2.4.0" }, "dependencies": { "discord-api-types": { - "version": "0.37.8", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.8.tgz", - "integrity": "sha512-uhol9KQ2moExZItMpuDMkf0R7sqqNHqcJBFN7S5iSdXBVCMRO7sC0GoyuRrv6ZDBYxoFU6nDy4dv0nld/aysqA==" + "version": "0.37.14", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.14.tgz", + "integrity": "sha512-byBH7SfDCMJwxdqeS8k5sihltH88/YPhuwx+vF2cftSxFLdxyHyU/ZxDL3bq+LB2c4ls/TymE76/ISlLfniUXg==" } } }, "@discordjs/collection": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.1.0.tgz", - "integrity": "sha512-PQ2Bv6pnT7aGPCKWbvvNRww5tYCGpggIQVgpuF9TdDPeR6n6vQYxezXiLVOS9z2B62Dp4c+qepQ15SgJbLYtCQ==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.2.0.tgz", + "integrity": "sha512-VvrrtGb7vbfPHzbhGq9qZB5o8FOB+kfazrxdt0OtxzSkoBuw9dURMkCwWizZ00+rDpiK2HmLHBZX+y6JsG9khw==" + }, + "@discordjs/util": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.1.0.tgz", + "integrity": "sha512-e7d+PaTLVQav6rOc2tojh2y6FE8S7REkqLldq1XF4soCx74XB/DIjbVbVLtBemf0nLW77ntz0v+o5DytKwFNLQ==" }, "@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -3410,9 +3441,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", + "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -3420,10 +3451,10 @@ "minimatch": "^3.0.4" } }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true }, "@humanwhocodes/object-schema": { @@ -3519,22 +3550,23 @@ } }, "@prisma/client": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.3.1.tgz", - "integrity": "sha512-FA0/d1VMJNWqzU7WVWTNWJ+lGOLR9JUBnF73GdIPAEVo/6dWk4gHx0EmgeU+SMv4MZoxgOeTBJF2azhg7x0hMw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.5.0.tgz", + "integrity": "sha512-B2cV0OPI1smhdYUxsJoLYQLoMlLH06MUxgFUWQnHodGMX98VRVXKmQE/9OcrTNkqtke5RC+YU24Szxd04tZA2g==", "requires": { - "@prisma/engines-version": "4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b" + "@prisma/engines-version": "4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452" } }, "@prisma/engines": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.3.1.tgz", - "integrity": "sha512-4JF/uMaEDAPdcdZNOrnzE3BvrbGpjgV0FcPT3EVoi6I86fWkloqqxBt+KcK/+fIRR0Pxj66uGR9wVH8U1Y13JA==" + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.5.0.tgz", + "integrity": "sha512-4t9ir2SbQQr/wMCNU4YpHWp5hU14J2m3wHUZnGJPpmBF8YtkisxyVyQsKd1e6FyLTaGq8LOLhm6VLYHKqKNm+g==", + "devOptional": true }, "@prisma/engines-version": { - "version": "4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b.tgz", - "integrity": "sha512-8yWpXkQRmiSfsi2Wb/ZS5D3RFbeu/btL9Pm/gdF4phB0Lo5KGsDFMxFMgaD64mwED2nHc8ZaEJg/+4Jymb9Znw==" + "version": "4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452.tgz", + "integrity": "sha512-o7LyVx8PPJBLrEzLl6lpxxk2D5VnlM4Fwmrbq0NoT6pr5aa1OuHD9ZG+WJY6TlR/iD9bhmo2LNcxddCMr5Rv2A==" }, "@sapphire/async-queue": { "version": "1.5.0", @@ -3547,32 +3579,35 @@ "integrity": "sha512-oFZYl7Prtqy8nD3ymmMpSMRy9Sdhp8E5PSI8n3OoBkHr4eSBvoOcBTxKapvRkHWes+amWeH/uB4UH31x7mG0KQ==" }, "@sapphire/discord.js-utilities": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-5.0.0.tgz", - "integrity": "sha512-XvXkL0/e4AwKIipSxPeNNa8UPmSCoc+vwkNrnvV43a0JUJ1acxPPWrcpxAzE9lRxPY/vDLYaaEw7M/hkg3i5xQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-5.1.1.tgz", + "integrity": "sha512-xWiduo2kYXMJ2IHKYjPGzL6VisTP/kwVh61BlxBbnPOKQ87F3EYe4WuXuX7JqoPUZVdRSG3ZuBgrz0mKGF4p3w==", "requires": { "@sapphire/discord-utilities": "^2.11.6", - "@sapphire/time-utilities": "^1.7.6", - "@sapphire/utilities": "^3.9.2", + "@sapphire/duration": "^1.0.0", + "@sapphire/utilities": "^3.11.0", "tslib": "^2.4.0" } }, + "@sapphire/duration": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/duration/-/duration-1.0.0.tgz", + "integrity": "sha512-B+6nKYnBmIlqqbamcR4iBvbQHz6/Kq2JUVM0rA3lQ+aYUYDdcA1Spt66CKtPWwdTYEtSv0VY6Jv27WCtFNYTUg==" + }, "@sapphire/framework": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.1.1.tgz", - "integrity": "sha512-dWWIhqFwVZ7nMJ6o7mIhgOAQhSfaue6IPyRSYhXuLEOU9uiQpLioXaYckVAVspRGAc5MqIalOV2htjQF2nCgjw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.1.3.tgz", + "integrity": "sha512-YHB6oeY095vrRv8ksW0zm/GSWuw+vDLvU0BzJBTGI0KYQfNq2d6OVCjY0ADxFgQSgC9AxOHj2h2GvGcLET+S4g==", "requires": { "@discordjs/builders": "^0.16.0", "@sapphire/discord-utilities": "^2.11.6", - "@sapphire/discord.js-utilities": "^5.0.0", - "@sapphire/lexure": "^1.0.2", - "@sapphire/pieces": "^3.5.1", - "@sapphire/ratelimits": "^2.4.4", - "@sapphire/result": "^2.4.1", - "@sapphire/stopwatch": "^1.4.1", - "@sapphire/utilities": "^3.9.3", - "@types/object-hash": "^2.2.1", - "object-hash": "^3.0.0", + "@sapphire/discord.js-utilities": "^5.0.1", + "@sapphire/lexure": "^1.1.1", + "@sapphire/pieces": "^3.5.2", + "@sapphire/ratelimits": "^2.4.5", + "@sapphire/result": "^2.5.0", + "@sapphire/stopwatch": "^1.5.0", + "@sapphire/utilities": "^3.10.0", "tslib": "^2.4.0" }, "dependencies": { @@ -3596,92 +3631,91 @@ } }, "@sapphire/lexure": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.0.2.tgz", - "integrity": "sha512-KKKcCvjkB6AImGzpWdrbLVI++VnRinpus+a4yu+PUT7zUlzUZdma1P/P8XlRDFEx6U+d5jk8ygKyTPzQKvkqRA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.1.2.tgz", + "integrity": "sha512-+v3P3EMDdFoybHH7c7cMcz30jEyxujkxWu5f958cf/Sm27fMM0IqwILnNFUpExZCBAueEM/eoSgbRl4q+K+0jg==", "requires": { - "@sapphire/result": "^2.4.1" + "@sapphire/result": "^2.6.0" } }, "@sapphire/pieces": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.1.tgz", - "integrity": "sha512-GEm7W6hAMC1yN76z0SZlIij66MDcuvWf7ra2TPGhflmv5ZUG4vNHNMktexP4AwEgKeF1jKJouVrIs3lAC3e4ZQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.2.tgz", + "integrity": "sha512-B8ghwre5naTIMnJIlqJGhKX6ZTpGqz4oAtBd/ihX0CY69cPtbem3VHfZ8Sf5C+50l3mfe2AU7CfZQn9kLQR2fQ==", "requires": { - "@discordjs/collection": "^1.0.1", - "@sapphire/utilities": "^3.9.2", + "@discordjs/collection": "^1.1.0", + "@sapphire/utilities": "^3.10.0", "tslib": "^2.4.0" } }, "@sapphire/plugin-scheduled-tasks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.0.tgz", - "integrity": "sha512-MIYiG40HW9kPeZGPcGlLX3uPkKaruG2GIkUhu5gNS1kJogtx6NdZlY5hKBDnpjl1jND5+d2gX9aaLNFA7+UxKA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.1.tgz", + "integrity": "sha512-vLxfHBu2vKaJZ9v2f4z+VDZaPeDqS8bm+Sc2minRwJPw1hWAHiPqmxCBPIONY7eOQ9qKayvhKYTIwwruxgO/Mg==", "requires": { - "@sapphire/time-utilities": "^1.7.6", + "@sapphire/stopwatch": "^1.4.1", + "@sapphire/utilities": "^3.9.3", "tslib": "^2.4.0" } }, "@sapphire/plugin-subcommands": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@sapphire/plugin-subcommands/-/plugin-subcommands-3.2.1.tgz", - "integrity": "sha512-I+NmbewS85oEfFx/0t8cGtimLmNGMzF6k5eigUmRakb7t6m1EK54cvWwV3zFbkhCMWI6e+ObiIe5XJVel8oWqg==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-subcommands/-/plugin-subcommands-3.2.3.tgz", + "integrity": "sha512-xUDkHdOXmqquO++I54ZOZg8Prh2YIJ7sSGBLXCU+FiNDbsfzbxr/McCfnKL65L6RBYOjf8d06up3GKPL8t9GpQ==", "requires": { - "@sapphire/utilities": "^3.9.2", + "@sapphire/utilities": "^3.11.0", "tslib": "^2.4.0" } }, "@sapphire/ratelimits": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@sapphire/ratelimits/-/ratelimits-2.4.4.tgz", - "integrity": "sha512-9gZ1BaY99HLWOcfuhlu0WklirHhVc6QD1pm5/v2W0O9pBpMHrd1GImVMXjYZRoy1qpmE2ZggSmN1665lktTCMw==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@sapphire/ratelimits/-/ratelimits-2.4.5.tgz", + "integrity": "sha512-2wqpVPRaPUE+CWStLm6wGLj1uA4Ln/9qbH4Ue/eCHC6/R5lJz0+8nGD1LpiYOcyeVLTHbmwODGeD92obkPej2g==", "requires": { - "@sapphire/time-utilities": "^1.7.4" + "@sapphire/timer-manager": "^1.0.0" } }, "@sapphire/result": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.4.1.tgz", - "integrity": "sha512-RWgp+cCm1dhE/voMGwp3z5xGmsOluXW9EPIXyO+khMXxZDL3iAgp4/ZCSFEw3nI98njwGmgWYIzdQfCu3WA4OA==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.6.0.tgz", + "integrity": "sha512-gdW6n/oDZ8aC1439Ub3RiLQ6L4VHAxbN0AhGJWNkEZ6Z6Ww2V62fwRiA/73OPfgYQKXk9ljhAFiqNO91KAonHQ==" }, "@sapphire/shapeshift": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.6.0.tgz", - "integrity": "sha512-tu2WLRdo5wotHRvsCkspg3qMiP6ETC3Q1dns1Q5V6zKUki+1itq6AbhMwohF9ZcLoYqg+Y8LkgRRtVxxTQVTBQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.7.0.tgz", + "integrity": "sha512-A6vI1zJoxhjWo4grsxpBRBgk96SqSdjLX5WlzKp9H+bJbkM07mvwcbtbVAmUZHbi/OG3HLfiZ1rlw4BhH6tsBQ==", "requires": { "fast-deep-equal": "^3.1.3", "lodash.uniqwith": "^4.5.0" } }, "@sapphire/stopwatch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@sapphire/stopwatch/-/stopwatch-1.4.1.tgz", - "integrity": "sha512-FoZIM7oQ1kwkjWpl/rKReuDFSlkCDjDp//1Np2mmQD+xQ2Zyo/J2MaYAITprwQr3AUBu/OOUJvqm7f8lA9R7gA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/stopwatch/-/stopwatch-1.5.0.tgz", + "integrity": "sha512-DtyKugdy3JTqm6JnEepTY64fGJAqlusDVrlrzifEgSCfGYCqpvB+SBldkWtDH+z+zLcp+PyaFLq7xpVfkhmvGg==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.4.0" } }, - "@sapphire/time-utilities": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@sapphire/time-utilities/-/time-utilities-1.7.6.tgz", - "integrity": "sha512-VsMVYFmS9Iu0buPs7gwn1D6vqIC04ezVMBRIo8vRTB2s7UNN/vQReX2cLABFoDVqs7RHQsvr2DPoTWHEDYw9YA==", - "requires": { - "@sapphire/utilities": "^3.9.2" - } + "@sapphire/timer-manager": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/timer-manager/-/timer-manager-1.0.0.tgz", + "integrity": "sha512-vxxnv75QPMGKt6IB6nL2xRJfwzcUQ9DBGzJLg6G8eS5O4u7j3IR/yr/GQsa4gIpjw6kQOgn8lUdnSTlpnERTbQ==" }, "@sapphire/ts-config": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/@sapphire/ts-config/-/ts-config-3.3.4.tgz", "integrity": "sha512-mWEUxCXh3cHKI7C8HJ049exVTMNaq+A/lJEDfM5ENSQ/OOZHd5DdmXn2jrYqFWbTRCHa0Vp2FAmACWBwePsBtg==", + "dev": true, "requires": { "tslib": "^2.3.1", "typescript": "^4.6.3" } }, "@sapphire/utilities": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.9.3.tgz", - "integrity": "sha512-7+ZjfbmRHqewmH32jpZfzrEuHpvTttTG7WjDl1GUtc4pkOMr0kYybrZmIEZYsUvF7PWzO0GrmOK2zWs3GuJo7g==" + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.11.0.tgz", + "integrity": "sha512-ich7J+329UTEgWxgk8b871rMhbFW/hvXdabdiKaUKd6g10eIMkIakWf+EGkDQsiDSiebIXll9TIPPmWtN3cVSw==" }, "@tsconfig/node10": { "version": "1.0.9", @@ -3725,9 +3759,9 @@ "dev": true }, "@types/node": { - "version": "18.7.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz", - "integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==" + "version": "18.11.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz", + "integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==" }, "@types/node-fetch": { "version": "2.6.2", @@ -3750,10 +3784,11 @@ } } }, - "@types/object-hash": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-2.2.1.tgz", - "integrity": "sha512-i/rtaJFCsPljrZvP/akBqEwUP2y5cZLOmvO+JaYnz01aPknrQ+hB5MRcO7iqCUsFaYfTG8kGfKUyboA07xeDHQ==" + "@types/semver": { + "version": "7.3.12", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz", + "integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==", + "dev": true }, "@types/ws": { "version": "8.5.3", @@ -3764,16 +3799,15 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.2.tgz", - "integrity": "sha512-OwwR8LRwSnI98tdc2z7mJYgY60gf7I9ZfGjN5EjCwwns9bdTuQfAXcsjSB2wSQ/TVNYSGKf4kzVXbNGaZvwiXw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.1.tgz", + "integrity": "sha512-FsWboKkWdytGiXT5O1/R9j37YgcjO8MKHSUmWnIEjVaz0krHkplPnYi7mwdb+5+cs0toFNQb0HIrN7zONdIEWg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/type-utils": "5.36.2", - "@typescript-eslint/utils": "5.36.2", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/type-utils": "5.40.1", + "@typescript-eslint/utils": "5.40.1", "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", "regexpp": "^3.2.0", "semver": "^7.3.7", @@ -3781,53 +3815,53 @@ } }, "@typescript-eslint/parser": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.36.2.tgz", - "integrity": "sha512-qS/Kb0yzy8sR0idFspI9Z6+t7mqk/oRjnAYfewG+VN73opAUvmYL3oPIMmgOX6CnQS6gmVIXGshlb5RY/R22pA==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.1.tgz", + "integrity": "sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/typescript-estree": "5.40.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.36.2.tgz", - "integrity": "sha512-cNNP51L8SkIFSfce8B1NSUBTJTu2Ts4nWeWbFrdaqjmn9yKrAaJUBHkyTZc0cL06OFHpb+JZq5AUHROS398Orw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.1.tgz", + "integrity": "sha512-jkn4xsJiUQucI16OLCXrLRXDZ3afKhOIqXs4R3O+M00hdQLKR58WuyXPZZjhKLFCEP2g+TXdBRtLQ33UfAdRUg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2" + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/visitor-keys": "5.40.1" } }, "@typescript-eslint/type-utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.36.2.tgz", - "integrity": "sha512-rPQtS5rfijUWLouhy6UmyNquKDPhQjKsaKH0WnY6hl/07lasj8gPaH2UD8xWkePn6SC+jW2i9c2DZVDnL+Dokw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.1.tgz", + "integrity": "sha512-DLAs+AHQOe6n5LRraXiv27IYPhleF0ldEmx6yBqBgBLaNRKTkffhV1RPsjoJBhVup2zHxfaRtan8/YRBgYhU9Q==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.36.2", - "@typescript-eslint/utils": "5.36.2", + "@typescript-eslint/typescript-estree": "5.40.1", + "@typescript-eslint/utils": "5.40.1", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.2.tgz", - "integrity": "sha512-9OJSvvwuF1L5eS2EQgFUbECb99F0mwq501w0H0EkYULkhFa19Qq7WFbycdw1PexAc929asupbZcgjVIe6OK/XQ==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.1.tgz", + "integrity": "sha512-Icg9kiuVJSwdzSQvtdGspOlWNjVDnF3qVIKXdJ103o36yRprdl3Ge5cABQx+csx960nuMF21v8qvO31v9t3OHw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.2.tgz", - "integrity": "sha512-8fyH+RfbKc0mTspfuEjlfqA4YywcwQK2Amcf6TDOwaRLg7Vwdu4bZzyvBZp4bjt1RRjQ5MDnOZahxMrt2l5v9w==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.1.tgz", + "integrity": "sha512-5QTP/nW5+60jBcEPfXy/EZL01qrl9GZtbgDZtDPlfW5zj/zjNrdI2B5zMUHmOsfvOr2cWqwVdWjobCiHcedmQA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/visitor-keys": "5.36.2", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/visitor-keys": "5.40.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3836,26 +3870,28 @@ } }, "@typescript-eslint/utils": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.36.2.tgz", - "integrity": "sha512-uNcopWonEITX96v9pefk9DC1bWMdkweeSsewJ6GeC7L6j2t0SJywisgkr9wUTtXk90fi2Eljj90HSHm3OGdGRg==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.1.tgz", + "integrity": "sha512-a2TAVScoX9fjryNrW6BZRnreDUszxqm9eQ9Esv8n5nXApMW0zeANUYlwh/DED04SC/ifuBvXgZpIK5xeJHQ3aw==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.36.2", - "@typescript-eslint/types": "5.36.2", - "@typescript-eslint/typescript-estree": "5.36.2", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/typescript-estree": "5.40.1", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.36.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.2.tgz", - "integrity": "sha512-BtRvSR6dEdrNt7Net2/XDjbYKU5Ml6GqJgVfXT0CxTCJlnIqK7rAGreuWKMT2t8cFUT2Msv5oxw0GMRD7T5J7A==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.1.tgz", + "integrity": "sha512-A2DGmeZ+FMja0geX5rww+DpvILpwo1OsiQs0M+joPWJYsiEFBLsH0y1oFymPNul6Z5okSmHpP4ivkc2N0Cgfkw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.36.2", + "@typescript-eslint/types": "5.40.1", "eslint-visitor-keys": "^3.3.0" } }, @@ -3975,9 +4011,9 @@ } }, "bullmq": { - "version": "1.90.1", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.90.1.tgz", - "integrity": "sha512-JY8mNzfnl+lfzFFzLJa6if+4YFvCMuJZDtQ8gvkcedoet+fDPEETF0iZ2fuzxCizuneARCniAiwIR/ESnqbuKw==", + "version": "1.91.1", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.91.1.tgz", + "integrity": "sha512-u7dat9I8ZwouZ651AMZkBSvB6NVUPpnAjd4iokd9DM41whqIBnDjuL11h7+kEjcpiDKj6E+wxZiER00FqirZQg==", "requires": { "cron-parser": "^4.6.0", "get-port": "6.1.2", @@ -3987,7 +4023,7 @@ "msgpackr": "^1.6.2", "semver": "^7.3.7", "tslib": "^2.0.0", - "uuid": "^8.3.2" + "uuid": "^9.0.0" } }, "call-bind": { @@ -4017,9 +4053,9 @@ } }, "cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==" }, "color-convert": { "version": "2.0.1", @@ -4134,19 +4170,19 @@ "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg==" }, "discord.js": { - "version": "13.10.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.3.tgz", - "integrity": "sha512-cIARuxfpQDeqA9Zw3fz4IL20xAhtMsjwJIf7/K82R3n2xROG9/fAx+7qjX8ysp9BfflYqMu2ZskyWq1EAmL5BA==", + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.12.0.tgz", + "integrity": "sha512-K5qhREsYcTHkEqt7+7LcSoXTeQYZpI+SQRs9ei/FhbhUpirmjqFtN99P8W2mrKUyhhy7WXWm7rnna0AooKtIpw==", "requires": { "@discordjs/builders": "^0.16.0", "@discordjs/collection": "^0.7.0", "@sapphire/async-queue": "^1.5.0", "@types/node-fetch": "^2.6.2", "@types/ws": "^8.5.3", - "discord-api-types": "^0.33.3", + "discord-api-types": "^0.33.5", "form-data": "^4.0.0", "node-fetch": "^2.6.7", - "ws": "^8.8.1" + "ws": "^8.9.0" }, "dependencies": { "@discordjs/builders": { @@ -4185,27 +4221,27 @@ } }, "dotenv": { - "version": "16.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz", - "integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==" + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" }, "es-abstract": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", - "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.2", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -4215,6 +4251,7 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -4247,14 +4284,14 @@ "dev": true }, "eslint": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz", - "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", + "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.10.5", + "@humanwhocodes/module-importer": "^1.0.1", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -4264,13 +4301,12 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", "globby": "^11.1.0", @@ -4279,6 +4315,7 @@ "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -4289,8 +4326,7 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "dependencies": { "eslint-scope": { @@ -4524,9 +4560,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -4645,12 +4681,6 @@ "functions-have-names": "^1.2.2" } }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -4658,9 +4688,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -4879,15 +4909,15 @@ } }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "requires": { "has": "^1.0.3" @@ -4990,6 +5020,12 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "js-sdsl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -5074,9 +5110,9 @@ } }, "luxon": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.3.tgz", - "integrity": "sha512-+EfHWnF+UT7GgTnq5zXg3ldnTKL2zdv7QJgsU5bjjpbH17E3qi/puMhQyJVYuCq+FRkogvB5WB6iVvUr+E4a7w==" + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", + "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==" }, "make-error": { "version": "1.3.6", @@ -5122,9 +5158,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, "ms": { @@ -5133,11 +5169,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "msgpackr": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.6.2.tgz", - "integrity": "sha512-bqSQ0DYJbXbrJcrZFmMygUZmqQiDfI2ewFVWcrZY12w5XHWtPuW4WppDT/e63Uu311ajwkRRXSoF0uILroBeTA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.7.2.tgz", + "integrity": "sha512-mWScyHTtG6TjivXX9vfIy2nBtRupaiAj0HQ2mtmpmYujAmqZmaaEVPaSZ1NKLMvicaMLFzEaMk0ManxMRg8rMQ==", "requires": { - "msgpackr-extract": "^2.0.2" + "msgpackr-extract": "^2.1.2" } }, "msgpackr-extract": { @@ -5175,11 +5211,6 @@ "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", "optional": true }, - "object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" - }, "object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -5318,11 +5349,12 @@ "dev": true }, "prisma": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.3.1.tgz", - "integrity": "sha512-90xo06wtqil76Xsi3mNpc4Js3SdDRR5g4qb9h+4VWY4Y8iImJY6xc3PX+C9xxTSt1lr0Q89A0MLkJjd8ax6KiQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.5.0.tgz", + "integrity": "sha512-9Aeg4qiKlv9Wsjz4NO8k2CzRzlvS3A4FYVJ5+28sBBZ0eEwbiVOE/Jj7v6rZC1tFW2s4GSICQOAyuOjc6WsNew==", + "devOptional": true, "requires": { - "@prisma/engines": "4.3.1" + "@prisma/engines": "4.5.0" } }, "punycode": { @@ -5424,10 +5456,21 @@ "queue-microtask": "^1.2.2" } }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "requires": { "lru-cache": "^6.0.0" } @@ -5622,9 +5665,9 @@ "dev": true }, "typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==" + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==" }, "unbox-primitive": { "version": "1.0.2", @@ -5648,15 +5691,9 @@ } }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, "v8-compile-cache-lib": { "version": "3.0.1", @@ -5711,9 +5748,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", "requires": {} }, "yallist": { diff --git a/package.json b/package.json index 66ccf9b..df446a7 100644 --- a/package.json +++ b/package.json @@ -26,31 +26,31 @@ }, "homepage": "https://github.com/veganhacktivists/arabot#readme", "dependencies": { - "@discordjs/builders": "^1.2.0", + "@discordjs/builders": "^1.3.0", "@prisma/client": "^4.0.0", "@sapphire/discord.js-utilities": "^5.0.0", - "@sapphire/framework": "^3.1.1", + "@sapphire/framework": "^3.1.3", "@sapphire/plugin-scheduled-tasks": "^4.0.0", "@sapphire/plugin-subcommands": "^3.0.0", "@sapphire/stopwatch": "^1.4.1", - "@sapphire/ts-config": "^3.3.4", "@sapphire/utilities": "^3.9.2", "@types/node": "^18.0.3", "bullmq": "^1.89.1", "discord-api-types": "^0.33.3", - "discord.js": "^13.10.3", + "discord.js": "^13.12.0", "dotenv": "^16.0.1", - "prisma": "^4.2.1", "ts-node": "^10.8.2", "typescript": "^4.7.4" }, "devDependencies": { + "@sapphire/ts-config": "^3.3.4", "@types/ioredis": "^4.28.10", "@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/parser": "^5.30.7", "eslint": "8.22.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.0.0", - "eslint-plugin-import": "^2.26.0" + "eslint-plugin-import": "^2.26.0", + "prisma": "^4.4.0" } } diff --git a/prisma/migrations/20220806153942_/migration.sql b/prisma/migrations/20220806153942_/migration.sql new file mode 100644 index 0000000..066741c --- /dev/null +++ b/prisma/migrations/20220806153942_/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - You are about to drop the column `balance` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `lastDaily` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `level` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `xp` on the `User` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "User" DROP COLUMN "balance", +DROP COLUMN "lastDaily", +DROP COLUMN "level", +DROP COLUMN "xp"; diff --git a/prisma/migrations/20220806162141_verification_channel/migration.sql b/prisma/migrations/20220806162141_verification_channel/migration.sql new file mode 100644 index 0000000..3c49694 --- /dev/null +++ b/prisma/migrations/20220806162141_verification_channel/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - Added the required column `channelId` to the `VerifyUnblock` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Verify" ADD COLUMN "channelId" TEXT NOT NULL; diff --git a/prisma/migrations/20220806193317_verification_time/migration.sql b/prisma/migrations/20220806193317_verification_time/migration.sql new file mode 100644 index 0000000..6ea66f1 --- /dev/null +++ b/prisma/migrations/20220806193317_verification_time/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - You are about to drop the column `time` on the `VerifyUnblock` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "Verify" DROP COLUMN "time", +ADD COLUMN "finishTime" TIMESTAMP(3), +ADD COLUMN "startTime" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; diff --git a/prisma/migrations/20220806194157_verification_time/migration.sql b/prisma/migrations/20220806194157_verification_time/migration.sql new file mode 100644 index 0000000..576590b --- /dev/null +++ b/prisma/migrations/20220806194157_verification_time/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "Verify" ADD COLUMN "joinTime" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, +ALTER COLUMN "startTime" DROP NOT NULL; diff --git a/prisma/migrations/20220806202004_change_id/migration.sql b/prisma/migrations/20220806202004_change_id/migration.sql new file mode 100644 index 0000000..d4fec5f --- /dev/null +++ b/prisma/migrations/20220806202004_change_id/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - The primary key for the `VerifyUnblock` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `channelId` on the `VerifyUnblock` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "Verify" DROP CONSTRAINT "Verify_pkey", +DROP COLUMN "channelId", +ALTER COLUMN "id" DROP DEFAULT, +ALTER COLUMN "id" SET DATA TYPE TEXT, +ADD CONSTRAINT "Verify_pkey" PRIMARY KEY ("id"); +DROP SEQUENCE "Verify_id_seq"; diff --git a/prisma/migrations/20220806203429_verify_date/migration.sql b/prisma/migrations/20220806203429_verify_date/migration.sql new file mode 100644 index 0000000..4c82c7e --- /dev/null +++ b/prisma/migrations/20220806203429_verify_date/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Verify" ALTER COLUMN "startTime" DROP DEFAULT; diff --git a/prisma/migrations/20220826220735_verification_info/migration.sql b/prisma/migrations/20220826220735_verification_info/migration.sql new file mode 100644 index 0000000..d613c76 --- /dev/null +++ b/prisma/migrations/20220826220735_verification_info/migration.sql @@ -0,0 +1,10 @@ +-- AlterTable +ALTER TABLE "Verify" ADD COLUMN "activist" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "food" INTEGER, +ADD COLUMN "length" INTEGER, +ADD COLUMN "life" INTEGER, +ADD COLUMN "reason" INTEGER, +ADD COLUMN "reasoning" INTEGER, +ADD COLUMN "trusted" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "vegCurious" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "where" INTEGER; diff --git a/prisma/migrations/20220826221107_add_ver_convinced/migration.sql b/prisma/migrations/20220826221107_add_ver_convinced/migration.sql new file mode 100644 index 0000000..4ae2e1c --- /dev/null +++ b/prisma/migrations/20220826221107_add_ver_convinced/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Verify" ADD COLUMN "convinced" BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 796dbdd..3e4f17f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -27,10 +27,6 @@ datasource db { model User { id String @id @db.VarChar(255) - level Int @default(0) - xp Int @default(0) - balance Int @default(0) - lastDaily DateTime? vegan Boolean @default(false) trusted Boolean @default(false) activist Boolean @default(false) @@ -52,16 +48,31 @@ model User { } model Verify { - id Int @id @default(autoincrement()) - user User @relation("verUser", fields: [userId], references: [id]) + id String @id + user User @relation("verUser", fields: [userId], references: [id]) userId String - verifier User? @relation("verVerifier", fields: [verifierId], references: [id]) + verifier User? @relation("verVerifier", fields: [verifierId], references: [id]) verifierId String? - time DateTime @default(now()) - timedOut Boolean @default(false) // If they got kicked out of verification because they timed out - vegan Boolean @default(false) // If they got verified as a vegan - text Boolean @default(false) // If they used text verification - serverVegan Boolean @default(false) // People that went vegan on the server + joinTime DateTime @default(now()) + startTime DateTime? + finishTime DateTime? + timedOut Boolean @default(false) // If they got kicked out of verification because they timed out + //complete Boolean @default(false) // If the verification was incomplete + // Roles they got from verification + vegan Boolean @default(false) // If they got verified as a vegan + activist Boolean @default(false) // If they got the activist role when they verified + trusted Boolean @default(false) // If they got the trusted role when they verified + vegCurious Boolean @default(false) // If they got the Veg Curious role + convinced Boolean @default(false) + text Boolean @default(false) // If they used text verification + serverVegan Boolean @default(false) // People that went vegan on the server + // Stats on verification + reason Int? + where Int? + length Int? + reasoning Int? + life Int? + food Int? notes String? } diff --git a/src/commands/mod/sus.ts b/src/commands/mod/sus.ts index 098420b..d635970 100644 --- a/src/commands/mod/sus.ts +++ b/src/commands/mod/sus.ts @@ -21,113 +21,19 @@ import { Command, RegisterBehavior, Args } from '@sapphire/framework'; import { MessageEmbed, MessageActionRow, MessageButton, Constants, ButtonInteraction, } from 'discord.js'; -import type { Message, GuildMember } from 'discord.js'; -import { PrismaClient } from '@prisma/client'; import { isMessageInstance } from '@sapphire/discord.js-utilities'; -import { addExistingUser, userExists } from '../../utils/dbExistingUser'; +import { addExistingUser, userExists } from '../../utils/database/dbExistingUser'; +import { + addToDatabase, + findNotes, + getNote, + deactivateNote, + deactivateAllNotes, +} from '../../utils/database/sus'; import IDs from '../../utils/ids'; // TODO add a check when they join the server to give the user the sus role again -async function addToDatabase(userId: string, modId: string, message: string) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Add the user to the database - await prisma.sus.create({ - data: { - user: { - connect: { - id: userId, - }, - }, - mod: { - connect: { - id: modId, - }, - }, - note: message, - }, - }); - - // Close the database connection - await prisma.$disconnect(); -} - -// Get a list of sus notes from the user -async function findNotes(userId: string, active: boolean) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Query to get the specific user's sus notes - const note = await prisma.sus.findMany({ - where: { - userId, - active, - }, - }); - - // Close the database connection - await prisma.$disconnect(); - return note; -} - -// Get one note from the id -async function getNote(noteId: number) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Query to get the specific user's sus notes - const note = await prisma.sus.findUnique({ - where: { - id: noteId, - }, - }); - - // Close the database connection - await prisma.$disconnect(); - return note; -} - -async function deactivateNote(noteId: number) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Query to deactivate the specific sus note - await prisma.sus.update({ - where: { - id: noteId, - }, - data: { - active: false, - }, - }); - - // Close the database connection - await prisma.$disconnect(); -} - -async function deactivateAllNotes(userId: string) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Query to deactivate the specific user's sus notes - await prisma.sus.updateMany({ - where: { - userId: { - contains: userId, - }, - }, - data: { - active: false, - }, - }); - - // Close the database connection - await prisma.$disconnect(); -} - -// Main command class SusCommand extends Command { public constructor(context: Command.Context) { super(context, { diff --git a/src/listeners/verification/joinServer.ts b/src/listeners/verification/joinServer.ts new file mode 100644 index 0000000..a305481 --- /dev/null +++ b/src/listeners/verification/joinServer.ts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import { Listener } from '@sapphire/framework'; +import type { GuildMember } from 'discord.js'; +import { fetchRoles } from '../../utils/database/dbExistingUser'; +import IDs from '../../utils/ids'; +import { blockTime } from '../../utils/database/verification'; + +class VerificationReady extends Listener { + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, { + ...options, + once: true, + event: 'guildMemberAdd', + }); + } + + public async run(user: GuildMember) { + // Add basic roles + const roles = await fetchRoles(user.id); + + // Check if the user has a verification block + const timeout = await blockTime(user.id); + if (timeout > 0) { + roles.push(IDs.roles.verifyBlock); + } + + // Add roles if they don't have verification block + await user.roles.add(roles); + } +} + +export default VerificationReady; diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts new file mode 100644 index 0000000..8dfd570 --- /dev/null +++ b/src/listeners/verification/joinVC.ts @@ -0,0 +1,720 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import { container, Listener } from '@sapphire/framework'; +import type { + CategoryChannel, + ColorResolvable, + TextChannel, + VoiceChannel, + VoiceState, + GuildMember, + Guild, + User, +} from 'discord.js'; +import { + ButtonInteraction, + Constants, + MessageActionRow, + MessageButton, + MessageEmbed, +} from 'discord.js'; +import { time } from '@discordjs/builders'; +import { maxVCs, questionInfo, serverFind } from '../../utils/verificationConfig'; +import { joinVerification, startVerification, finishVerification } from '../../utils/database/verification'; +import { findNotes } from '../../utils/database/sus'; +import { userExists, addExistingUser } from '../../utils/database/dbExistingUser'; +import { rolesToString } from '../../utils/formatter'; +import IDs from '../../utils/ids'; + +class VerificationJoinVCListener extends Listener { + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, { + ...options, + event: 'voiceStateUpdate', + }); + } + + public async run(oldState: VoiceState, newState: VoiceState) { + // If the event was not a user joining the channel + if (oldState.channel?.parent?.id === IDs.categories.verification + || newState.channel?.parent?.id !== IDs.categories.verification + ) { + return; + } + + // Variable if this channel is a Verifiers only VC + let verifier = false; + + // Checks for not null + const { channel } = newState; + const { member } = newState; + const { client } = container; + const guild = client.guilds.cache.get(newState.guild.id); + + if (channel === null || member === null || guild === undefined) { + console.error('Verification channel not found'); + return; + } + + // Get current category and channel + const categoryGuild = guild.channels.cache.get(IDs.categories.verification); + const currentChannelGuild = guild.channels.cache.get(channel.id); + if (currentChannelGuild === undefined || categoryGuild === undefined) { + console.error('Verification channel not found'); + return; + } + const currentChannel = currentChannelGuild as VoiceChannel; + const category = categoryGuild as CategoryChannel; + + const roles = rolesToString(member.roles.cache.map((r) => r.id)); + + // Checks if a verifier has joined + if (channel.members.size === 2) { + await newState.channel!.permissionOverwrites.set([ + { + id: guild.roles.everyone, + allow: ['SEND_MESSAGES'], + }, + ]); + return; + } + + // Check if a verifier joined a verification VC and update database + if (channel.members.size === 2) { + if (!channel.name.includes(' - Verification')) { + return; + } + + await startVerification(channel.id); + return; + } + + // Checks if there is more than one person who has joined or if the channel has members + if (channel.members.size !== 1 + || !channel.members.has(member.id)) { + return; + } + + // Check if the user has the verifiers role + if (member.roles.cache.has(IDs.roles.staff.verifier) + || member.roles.cache.has(IDs.roles.staff.trialVerifier)) { + await channel.setName('Verifier Meeting'); + verifier = true; + } else { + await channel.setName(`${member.displayName} - Verification`); + await currentChannel.send(`Hiya ${member.user}, please be patient as a verifier has been called out to verify you.\n\n` + + 'If you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you\'d like to verify as a vegan again, you\'d have to contact a Mod, which could be done via ModMail.'); + // Adds to the database that the user joined verification + await joinVerification(channel.id, member); + + // Remove all roles from the user + await member.roles.remove([ + IDs.roles.vegan.vegan, + IDs.roles.trusted, + IDs.roles.nonvegan.nonvegan, + IDs.roles.nonvegan.convinced, + IDs.roles.nonvegan.vegCurious, + ]); + + // Start 15-minute timer if verifier does not join + // @ts-ignore + this.container.tasks.create('verifyTimeout', { + channelId: channel.id, + userId: member.id, + }, 900_000); // 15 minutes + } + + // Check how many voice channels there are + const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); + + // Create a text channel for verifiers only + // Checks if there are more than 10 voice channels + if (!verifier) { + const verificationText = await guild.channels.create(`✅┃${member.displayName}-verification`, { + type: 'GUILD_TEXT', + topic: `Channel for verifiers only. ${member.id} ${channel.id} (Please do not change this)`, + parent: category.id, + userLimit: 1, + permissionOverwrites: [ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'SEND_MESSAGES'], + }, + { + id: IDs.roles.staff.verifier, + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + + // Send a message that someone wants to be verified + const userInfoEmbed = await this.getUserInfo(member, roles); + const susNotes = await this.getSus(member, guild); + await verificationText.send({ + content: `${member.user} wants to be verified in ${channel} + \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`, + embeds: [userInfoEmbed, susNotes], + }); + + await this.verificationProcess(verificationText, channel.id, member, guild); + } + + // Create a new channel for others to join + + // Checks if there are more than 10 voice channels + if (listVoiceChannels.size > maxVCs - 1) { + await guild.channels.create('Verification', { + type: 'GUILD_VOICE', + parent: category.id, + userLimit: 1, + permissionOverwrites: [ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], + }, + { + id: IDs.roles.nonvegan.nonvegan, + allow: ['VIEW_CHANNEL'], + deny: ['CONNECT'], + }, + { + id: IDs.roles.vegan.vegan, + allow: ['VIEW_CHANNEL'], + deny: ['CONNECT'], + }, + { + id: IDs.roles.vegan.activist, + deny: ['VIEW_CHANNEL', 'CONNECT'], + }, + { + id: IDs.roles.staff.verifier, + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + } else { + await guild.channels.create('Verification', { + type: 'GUILD_VOICE', + parent: category.id, + userLimit: 1, + permissionOverwrites: [ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], + }, + { + id: IDs.roles.nonvegan.nonvegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.vegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.activist, + deny: ['VIEW_CHANNEL', 'CONNECT'], + }, + { + id: IDs.roles.staff.verifier, + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + } + + // Change permissions to join the current channel + await currentChannel.permissionOverwrites.set([ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: IDs.roles.nonvegan.nonvegan, + deny: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.vegan, + deny: ['VIEW_CHANNEL'], + }, + { + id: member.id, + allow: ['VIEW_CHANNEL'], + }, + ]); + await currentChannel.setUserLimit(0); + } + + // Creates an embed for information about the user + private async getUserInfo(user: GuildMember, roles: string) { + const joinTime = time(user.joinedAt!); + const registerTime = time(user.user.createdAt); + + const embed = new MessageEmbed() + .setColor(user.displayHexColor) + .setTitle(`Information on ${user.user.username}`) + .setThumbnail(user.user.avatarURL()!) + .addFields( + { name: 'Joined:', value: `${joinTime}`, inline: true }, + { name: 'Created:', value: `${registerTime}`, inline: true }, + { name: 'Roles:', value: roles }, + ); + + return embed; + } + + // Creates the embed to display the sus note + private async getSus(user: GuildMember, guild: Guild) { + const notes = await findNotes(user.id, true); + + const embed = new MessageEmbed() + .setColor(user.displayHexColor) + .setTitle(`${notes.length} sus notes for ${user.user.username}`); + + // Add up to 10 of the latest sus notes to the embed + for (let i = notes.length > 10 ? notes.length - 10 : 0; i < notes.length; i += 1) { + // Get mod name + const modGuildMember = guild!.members.cache.get(notes[i].modId); + let mod = notes[i].modId; + if (modGuildMember !== undefined) { + mod = modGuildMember!.displayName; + } + // Add sus note to embed + embed.addFields({ + name: `Sus ID: ${notes[i].id} | Moderator: ${mod} | Date: `, + value: notes[i].note, + }); + } + + return embed; + } + + private async verificationProcess( + channel: TextChannel, + verId: string, + user: GuildMember, + guild: Guild, + ) { + const embedColor = '#0099ff'; + const info = { + page: 0, + find: { + reason: 0, + where: 0, + }, + length: 0, + reasoning: 0, + life: 0, + food: 0, + roles: { + vegan: false, + activist: false, + trusted: false, + vegCurious: false, + convinced: false, + }, + }; + + // TODO add a variable that tells if each order has a reversed value, e.g. 0-3 or 3-0 + const questionLength = questionInfo.length; + + let embed = await this.createEmbed(questionInfo[0].question, embedColor); + let buttons = await this.createButtons(questionInfo[0].buttons); + + // Sends the note to verify this note is to be deleted + const message = await channel.send({ + embeds: [embed], + components: buttons, + }); + + // Listen for the button presses + const collector = channel.createMessageComponentCollector({ + // max: 2, // Maximum of 1 button press + }); + + // Button pressed + collector.on('collect', async (button: ButtonInteraction) => { + // Select roles + if (button.customId.includes('button')) { + await button.deferUpdate(); + // Get the button choice + const buttonChoice = this.getButtonValue(button.customId); + if (Number.isNaN(buttonChoice)) { + return; + } + // Set the value of the button choice to the page the question was on + switch (info.page) { + case 0: { + info.find.reason = buttonChoice; + if (buttonChoice !== 0 && info.find.reason === 0) { + embed = await this.createEmbed(serverFind[info.page].question, embedColor); + buttons = await this.createButtons(serverFind[info.page].buttons); + await message.edit({ + embeds: [embed], + components: buttons, + }); + return; + } + if (info.find.reason !== 0) { + info.find.where = buttonChoice; + } + break; + } + case 1: { + info.length = buttonChoice; + break; + } + case 2: { + info.reasoning = buttonChoice; + break; + } + case 3: { + info.life = buttonChoice; + break; + } + case 4: { + info.food = buttonChoice; + break; + } + // If they are definitely vegan or not + case 5: { + if (buttonChoice === 0) { + info.roles.vegan = true; + info.roles.trusted = true; + } else { + info.page += 1; + } + break; + } + // If they are vegan but should get activist role + case 6: { + if (buttonChoice === 0) { + info.roles.activist = true; + } + info.page += 1; + break; + } + // If they should get vegan, convinced or non-vegan + case 7: { + if (buttonChoice === 0) { + info.roles.vegan = true; + } else if (buttonChoice === 1) { + info.roles.convinced = true; + } + break; + } + case 8: { + if (buttonChoice === 0) { + info.roles.vegCurious = true; + } + break; + } + default: { + console.error('Button clicked out of range'); + return; + } + } + info.page += 1; + // Checks if finished all the questions + if (info.page < questionLength) { + embed = await this.createEmbed(questionInfo[info.page].question, embedColor); + buttons = await this.createButtons(questionInfo[info.page].buttons); + await message.edit({ + embeds: [embed], + components: buttons, + }); + } + // Confirmation to give roles to the user being verified + if (info.page === questionLength) { + // Create embed with all the roles the user has + embed = new MessageEmbed() + .setColor(embedColor) + .setTitle(`Give these roles to ${user.displayName}?`) + .setThumbnail(user.avatarURL()!) + .addFields( + { name: 'Roles:', value: this.getTextRoles(info.roles) }, + ); + + // Create buttons for input + buttons = [new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId('confirm') + .setLabel('Yes') + .setStyle(Constants.MessageButtonStyles.SUCCESS), + new MessageButton() + .setCustomId('cancel') + .setLabel('No') + .setStyle(Constants.MessageButtonStyles.DANGER), + )]; + await message.edit({ + embeds: [embed], + components: buttons, + }); + } + } + // Confirming and finishing the verification + if (button.customId === 'confirm' && info.page >= questionLength) { + // Check verifier is on the database + const verifierGuildMember = await guild.members.cache.get(button.user.id); + if (verifierGuildMember === undefined) { + await message.edit({ content: 'Verifier not found!' }); + return; + } + // Add verifier to database if they're not on the database + if (!(await userExists(verifierGuildMember))) { + await addExistingUser(verifierGuildMember); + } + + // Add verification data to database + await finishVerification(verId, button.user.id, info); + // Give roles on Discord + await this.giveRoles(user, info.roles); + // Add timeout if they do not have activist role + if (!info.roles.activist) { + // @ts-ignore + this.container.tasks.create('verifyUnblock', { + userId: user.id, + guildId: guild.id, + }, (info.roles.vegan || info.roles.convinced) ? 604800000 : 1814400000); + } + // Add embed saying verification completed + embed = new MessageEmbed() + .setColor('#34c000') + .setTitle(`Successfully verified ${user.displayName}!`) + .setThumbnail(user.user.avatarURL()!) + .addFields( + { name: 'Roles:', value: this.getTextRoles(info.roles) }, + ); + await message.edit({ + embeds: [embed], + components: [], + }); + // Send welcome message after verification + await this.finishMessages(user.user, info.roles); + } + if (button.customId === 'cancel' && info.page >= questionLength) { + info.page = 5; + info.roles.vegan = false; + info.roles.activist = false; + info.roles.trusted = false; + info.roles.vegCurious = false; + info.roles.convinced = false; + embed = await this.createEmbed(questionInfo[info.page].question, embedColor); + buttons = await this.createButtons(questionInfo[info.page].buttons); + await message.edit({ + embeds: [embed], + components: buttons, + }); + await button.deferUpdate(); + } + }); + } + + private async createEmbed(title: string, color: ColorResolvable) { + return new MessageEmbed() + .setColor(color) + .setTitle(title); + } + + private async createButtons(buttons: string[]) { + const buttonActions = []; + + for (let i = 0; i < buttons.length; i += 1) { + // Check if it exceeds the maximum buttons in a ActionRow + if (i % 5 === 0) { + buttonActions.push(new MessageActionRow()); + } + buttonActions[Math.floor(i / 5)] + .addComponents( + new MessageButton() + .setCustomId(`button${i}`) + .setLabel(buttons[i]) + .setStyle(Constants.MessageButtonStyles.SECONDARY), + ); + } + + return buttonActions; + } + + // Finds the value of the choice in the button + private getButtonValue(button: string) { + const buttonChoice = button.at(button.length - 1); + if (buttonChoice === undefined) { + return NaN; + } + return parseInt(buttonChoice, 10); + } + + private getTextRoles( + roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }, + ) { + let rolesText = ''; + if (roles.convinced) { + rolesText += `<@&${IDs.roles.nonvegan.convinced}>`; + } + if (roles.vegan) { + rolesText += `<@&${IDs.roles.vegan.vegan}>`; + } else { + rolesText += `<@&${IDs.roles.nonvegan.nonvegan}>`; + } + if (roles.activist) { + rolesText += `<@&${IDs.roles.vegan.activist}>`; + } + if (roles.trusted) { + rolesText += `<@&${IDs.roles.trusted}>`; + } + if (roles.vegCurious) { + rolesText += `<@&${IDs.roles.nonvegan.vegCurious}>`; + } + return rolesText; + } + + private async giveRoles( + user: GuildMember, + roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }, + ) { + const rolesAdd = []; + if (roles.convinced) { + rolesAdd.push(IDs.roles.nonvegan.convinced); + } + if (roles.vegan) { + rolesAdd.push(IDs.roles.vegan.vegan); + } else { + rolesAdd.push(IDs.roles.nonvegan.nonvegan); + } + if (roles.activist) { + rolesAdd.push(IDs.roles.vegan.activist); + } else { + rolesAdd.push(IDs.roles.verifyBlock); + } + if (roles.trusted) { + rolesAdd.push(IDs.roles.trusted); + } + if (roles.vegCurious) { + rolesAdd.push(IDs.roles.nonvegan.vegCurious); + } + await user.roles.add(rolesAdd); + } + + // Messages after verifying the user + private async finishMessages(user: User, roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }) { + // Send a DM with when their verification is finished + await this.finishDM(user, roles) + .catch(() => console.error('Verification: Closed DMs')); + + // Not vegan + if (!roles.vegan) { + const general = this.container.client.channels.cache.get(IDs.channels.nonVegan.general) as TextChannel | undefined; + if (general === undefined) { + return; + } + let msg = `${user}, you have been verified! Please check <#${IDs.channels.information.roles}> ` + + `and remember to follow the <#${IDs.channels.information.conduct}> and to respect ongoing discussion and debates.`; + // Add extra info if the user got veg curious or convinced. + if (roles.vegCurious || roles.convinced) { + msg += `\n\nYou also have access to <#${IDs.channels.dietSupport.main}> for help on going vegan.`; + } + await general.send(msg); + return; + } + + // Vegan + const general = this.container.client.channels.cache.get(IDs.channels.vegan.general) as TextChannel | undefined; + if (general === undefined) { + return; + } + const msg = `Welcome ${user}! Please check out <#${IDs.channels.information.roles}> :)`; + await general.send(msg); + + // Activist role + if (roles.activist) { + const activist = this.container.client.channels.cache.get(IDs.channels.activism.activism) as TextChannel | undefined; + if (activist === undefined) { + return; + } + const activistMsg = `${user} you have been given the activist role! This means that if you'd wish to engage with non-vegans in ` + + `<#${IDs.channels.nonVegan.general}>, you should follow these rules:\n\n` + + '1. Try to move conversations with non-vegans towards veganism/animal ethics\n' + + '2. Don\'t discuss social topics while activism is happening\n' + + '3. Have evidence for claims you make. "I don\'t know" is an acceptable answer. Chances are someone here knows or you can take time to find out\n' + + '4. Don\'t advocate for baby steps towards veganism. Participation in exploitation can stop today\n' + + '5. Differences in opinion between activists should be resolved in vegan spaces, not in the chat with non-vegans'; + await activist.send(activistMsg); + } + } + + // Messages after verifying the user + private async finishDM(user: User, roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }) { + if (!roles.vegan && !roles.convinced) { + const message = 'You\'ve been verified as non-vegan!' + + `\n\nYou can next verify on ${time(Math.round(Date.now() / 1000) + 1814400)}`; + + await user.send(message); + } else if (roles.convinced) { + const message = 'You\'ve been verified as convinced!' + + `\n\nYou can next verify on ${time(Math.round(Date.now() / 1000) + 604800)}`; + + await user.send(message); + } else if (roles.vegan && !roles.activist) { + const message = 'You\'ve been verified as a vegan!' + + `\n\nYou can next get verified on ${time(Math.round(Date.now() / 1000) + 604800)} if you would wish to have the activist role.`; + + await user.send(message); + } + } +} + +export default VerificationJoinVCListener; diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts new file mode 100644 index 0000000..47a64c8 --- /dev/null +++ b/src/listeners/verification/leaveVC.ts @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import { container, Listener } from '@sapphire/framework'; +import type { + VoiceState, CategoryChannel, VoiceChannel, TextChannel, +} from 'discord.js'; +import { time } from '@discordjs/builders'; +import { maxVCs, leaveBan } from '../../utils/verificationConfig'; +import { getUser, checkFinish, countIncomplete } from '../../utils/database/verification'; +import { fetchRoles } from '../../utils/database/dbExistingUser'; +import { fibonacci } from '../../utils/mathsSeries'; +import IDs from '../../utils/ids'; + +class VerificationLeaveVCListener extends Listener { + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, { + ...options, + event: 'voiceStateUpdate', + }); + } + + public async run(oldState: VoiceState, newState: VoiceState) { + // If the event was not a user joining the channel + if (oldState.channel?.parent?.id !== IDs.categories.verification + || newState.channel?.parent?.id === IDs.categories.verification + || oldState.channel.members.size > 0 + ) { + return; + } + + let verifier = false; + + // Check for undefined variables + const { client } = container; + const { channel } = oldState; + const guild = client.guilds.cache.get(newState.guild.id); + + if (channel === null || guild === undefined) { + console.error('Verification channel not found'); + return; + } + + // Get the category + const categoryGuild = guild.channels.cache.get(IDs.categories.verification); + if (categoryGuild === null) { + console.error('Verification channel not found'); + return; + } + const category = categoryGuild as CategoryChannel; + + // Get the user that was being verified + const userSnowflake = await getUser(channel.id); + if (userSnowflake === null) { + verifier = true; + } + + // Allow more people to join VC if there are less than 10 VCs + + if (!verifier) { + const user = guild.members.cache.get(userSnowflake!)!; + + // Remove verify as vegan and give non vegan role + if (!await checkFinish(channel.id)) { + await user.roles.remove(IDs.roles.verifyingAsVegan); + + // Get roles to give back to the user + const roles = await fetchRoles(user.id); + roles.push(IDs.roles.verifyBlock); + await user.roles.add(roles); + // Create timeout block for user + // Counts the recent times they have incomplete verifications + const incompleteCount = await countIncomplete(user.id) % (leaveBan + 1); + // Creates the length of the time for the ban + const banLength = fibonacci(incompleteCount) * 3600_000; + + // @ts-ignore + this.container.tasks.create('verifyUnblock', { + userId: user.id, + guildId: guild.id, + }, banLength); + + await user.user.send('You have been timed out as a verifier had not joined for 15 minutes or you disconnected from verification.\n\n' + + `You can verify again at: ${time(Math.round(Date.now() / 1000) + (banLength / 1000))}`) + .catch(() => console.error('Verification: Closed DMs')); + } + } + + // Check how many voice channels there are + const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); + + // Check that it is not deleting the 'Verification' channel (in case bot crashes) + if (channel.name !== 'Verification') { + // Delete the channel + await channel.delete(); + } + + // Delete text channel + if (!verifier) { + // Gets a list of all the text channels in the verification category + const listTextChannels = category.children.filter((c) => c.type === 'GUILD_TEXT'); + listTextChannels.forEach((c) => { + const textChannel = c as TextChannel; + // Checks if the channel topic has the user's snowflake + if (textChannel.topic!.includes(userSnowflake!)) { + textChannel.delete(); + } + }); + } + + // If there are no VCs left in verification after having the channel deleted + if (listVoiceChannels.size === 0) { + // Create a verification channel + await guild.channels.create('Verification', { + type: 'GUILD_VOICE', + parent: IDs.categories.verification, + userLimit: 1, + permissionOverwrites: [ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], + }, + { + id: IDs.roles.nonvegan.nonvegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.vegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.activist, + deny: ['VIEW_CHANNEL', 'CONNECT'], + }, + { + id: IDs.roles.staff.verifier, + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + } + + // If there are less than 10, stop + if (listVoiceChannels.size < maxVCs) { + return; + } + + const verification = listVoiceChannels.last() as VoiceChannel; + + await verification!.permissionOverwrites.set([ + { + id: IDs.roles.nonvegan.nonvegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.vegan, + allow: ['VIEW_CHANNEL'], + }, + ]); + } +} + +export default VerificationLeaveVCListener; diff --git a/src/listeners/verification/start.ts b/src/listeners/verification/start.ts new file mode 100644 index 0000000..2410702 --- /dev/null +++ b/src/listeners/verification/start.ts @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import { Listener } from '@sapphire/framework'; +import type { + Client, + CategoryChannel, + TextChannel, + VoiceChannel, +} from 'discord.js'; +import IDs from '../../utils/ids'; + +class VerificationReady extends Listener { + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, { + ...options, + once: true, + event: 'ready', + }); + } + + public async run(client: Client) { + // Get verification category + let category = client.channels.cache.get(IDs.categories.verification) as CategoryChannel | undefined; + if (category === undefined) { + category = await client.channels.fetch(IDs.categories.verification) as CategoryChannel | undefined; + if (category === undefined) { + console.error('verifyStart: Channel not found'); + return; + } + } + + // Check how many voice channels there are + let voiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); + const emptyVC: string[] = []; + // Delete voice channels + voiceChannels.forEach((c) => { + const voiceChannel = c as VoiceChannel; + if (voiceChannel.members.size === 0) { + emptyVC.push(voiceChannel.id); + voiceChannel.delete(); + } + }); + + // Delete text channels + const textChannels = category.children.filter((c) => c.type === 'GUILD_TEXT'); + textChannels.forEach((c) => { + const textChannel = c as TextChannel; + // Checks if the channel topic has the user's snowflake + emptyVC.forEach((snowflake) => { + if (textChannel.topic!.includes(snowflake)) { + textChannel.delete(); + } + }); + }); + + // Check if there is no voice channels, create verification + voiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); + if (voiceChannels.size === emptyVC.length) { + await category.guild.channels.create('Verification', { + type: 'GUILD_VOICE', + parent: IDs.categories.verification, + userLimit: 1, + permissionOverwrites: [ + { + id: category.guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], + }, + { + id: IDs.roles.nonvegan.nonvegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.vegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.activist, + deny: ['VIEW_CHANNEL', 'CONNECT'], + }, + { + id: IDs.roles.staff.verifier, + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + } + } +} + +export default VerificationReady; diff --git a/src/scheduled-tasks/verifyTimeout.ts b/src/scheduled-tasks/verifyTimeout.ts new file mode 100644 index 0000000..47a0a9d --- /dev/null +++ b/src/scheduled-tasks/verifyTimeout.ts @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import type { VoiceChannel } from 'discord.js'; +import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; + +export class VerifyTimeout extends ScheduledTask { + public constructor(context: ScheduledTask.Context, options: ScheduledTask.Options) { + super(context, options); + } + + public async run(payload: { channelId: string, userId: string }) { + // Get the guild where the user is in + let channel = this.container.client.channels.cache.get(payload.channelId) as VoiceChannel | undefined; + if (channel === undefined) { + channel = await this.container.client.channels.fetch(payload.channelId) as VoiceChannel | undefined; + if (channel === undefined) { + console.error('verifyTimeout: Channel not found!'); + return; + } + } + + if (channel.members.size < 2 && channel.members.has(payload.userId)) { + const user = channel.members.get(payload.userId); + if (user === undefined) { + console.error('verifyTimeout: GuildMember not found!'); + return; + } + await user.voice.disconnect(); + } + } +} + +declare module '@sapphire/plugin-scheduled-tasks' { + interface ScheduledTasks { + verifyUnblock: never; + } +} + +export default VerifyTimeout; diff --git a/src/scheduled-tasks/verifyUnblock.ts b/src/scheduled-tasks/verifyUnblock.ts new file mode 100644 index 0000000..5af8534 --- /dev/null +++ b/src/scheduled-tasks/verifyUnblock.ts @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; +import IDs from '../utils/ids'; + +export class VerifyUnblock extends ScheduledTask { + public constructor(context: ScheduledTask.Context, options: ScheduledTask.Options) { + super(context, options); + } + + public async run(payload: { userId: string, guildId: string }) { + // Get the guild where the user is in + let guild = this.container.client.guilds.cache.get(payload.guildId); + if (guild === undefined) { + guild = await this.container.client.guilds.fetch(payload.guildId); + if (guild === undefined) { + console.error('verifyUnblock: Guild not found!'); + return; + } + } + + // Find GuildMember for the user + let user = guild.members.cache.get(payload.userId); + if (user === undefined) { + user = await guild.members.fetch(payload.userId); + if (user === undefined) { + console.error('verifyUnblock: GuildMember not found!'); + return; + } + } + + // Remove the 'verify block' role + await user.roles.remove(IDs.roles.verifyBlock); + } +} + +declare module '@sapphire/plugin-scheduled-tasks' { + interface ScheduledTasks { + verifyUnblock: never; + } +} + +export default VerifyUnblock; diff --git a/src/utils/database/dbExistingUser.ts b/src/utils/database/dbExistingUser.ts new file mode 100644 index 0000000..b0a2831 --- /dev/null +++ b/src/utils/database/dbExistingUser.ts @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import type { GuildMember, GuildMemberRoleManager } from 'discord.js'; +import { PrismaClient } from '@prisma/client'; +import IDs from '../ids'; + +// Checks if the user exists on the database +export async function userExists(user: GuildMember) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Counts if the user is on the database by their snowflake + const userQuery = await prisma.user.count({ + where: { + id: user.id, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + + // If the user is found on the database, then return true, otherwise, false. + return userQuery > 0; +} + +function getRoles(roles: GuildMemberRoleManager) { + // Checks what roles the user has + const rolesDict = { + vegan: roles.cache.has(IDs.roles.vegan.vegan), + activist: roles.cache.has(IDs.roles.vegan.activist), + plus: roles.cache.has(IDs.roles.vegan.plus), + notVegan: roles.cache.has(IDs.roles.nonvegan.nonvegan), + vegCurious: roles.cache.has(IDs.roles.nonvegan.vegCurious), + convinced: roles.cache.has(IDs.roles.nonvegan.convinced), + trusted: roles.cache.has(IDs.roles.trusted), + muted: roles.cache.has(IDs.roles.restrictions.muted), + }; + + return rolesDict; +} + +// Adds the user to the database if they were already on the server before the bot/database +export async function addExistingUser(user: GuildMember) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Counts if the user is on the database by their snowflake + const userQuery = await prisma.user.count({ + where: { + id: user.id, + }, + }); + + // If the user is already in the database + if (userQuery > 0) { + return; + } + + // Parse all the roles into a dictionary + const roles = getRoles(user.roles); + + // Create the user in the database + await prisma.user.create({ + data: { + id: user.id, + vegan: roles.vegan, + trusted: roles.trusted, + activist: roles.activist, + plus: roles.plus, + notVegan: roles.notVegan, + vegCurious: roles.vegCurious, + convinced: roles.convinced, + muted: roles.muted, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} + +export async function updateUser(user: GuildMember) { + // Check if the user is already on the database + if (!(await userExists(user))) { + await addExistingUser(user); + return; + } + + // Parse all the roles into a dictionary + const roles = getRoles(user.roles); + + // Initialises Prisma Client + const prisma = new PrismaClient(); + + await prisma.user.update({ + where: { + id: user.id, + }, + data: { + id: user.id, + vegan: roles.vegan, + trusted: roles.trusted, + activist: roles.activist, + plus: roles.plus, + notVegan: roles.notVegan, + vegCurious: roles.vegCurious, + convinced: roles.convinced, + muted: roles.muted, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} + +export async function fetchRoles(user: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Get the user's roles + const roleQuery = await prisma.user.findUnique({ + where: { + id: user, + }, + select: { + vegan: true, + trusted: true, + activist: true, + plus: true, + notVegan: true, + vegCurious: true, + convinced: true, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + + // Assign roles to role snowflakes + const roles = []; + + if (roleQuery === null) { + roles.push(''); + return roles; + } + if (roleQuery.vegan) { + roles.push(IDs.roles.vegan.vegan); + } + if (roleQuery.trusted) { + roles.push(IDs.roles.trusted); + } + if (roleQuery.activist) { + roles.push(IDs.roles.vegan.activist); + } + if (roleQuery.plus) { + roles.push(IDs.roles.vegan.plus); + } + if (roleQuery.notVegan) { + roles.push(IDs.roles.nonvegan.nonvegan); + } + if (roleQuery.vegCurious) { + roles.push(IDs.roles.nonvegan.vegCurious); + } + if (roleQuery.convinced) { + roles.push(IDs.roles.nonvegan.convinced); + } + + return roles; +} diff --git a/src/utils/database/sus.ts b/src/utils/database/sus.ts new file mode 100644 index 0000000..5017868 --- /dev/null +++ b/src/utils/database/sus.ts @@ -0,0 +1,99 @@ +import { PrismaClient } from '@prisma/client'; + +export async function addToDatabase(userId: string, modId: string, message: string) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Add the user to the database + await prisma.sus.create({ + data: { + user: { + connect: { + id: userId, + }, + }, + mod: { + connect: { + id: modId, + }, + }, + note: message, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} + +// Get a list of sus notes from the user +export async function findNotes(userId: string, active: boolean) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Query to get the specific user's sus notes + const note = await prisma.sus.findMany({ + where: { + userId, + active, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + return note; +} + +// Get one note from the id +export async function getNote(noteId: number) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Query to get the specific user's sus notes + const note = await prisma.sus.findUnique({ + where: { + id: noteId, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + return note; +} + +export async function deactivateNote(noteId: number) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Query to deactivate the specific sus note + await prisma.sus.update({ + where: { + id: noteId, + }, + data: { + active: false, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} + +export async function deactivateAllNotes(userId: string) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Query to deactivate the specific user's sus notes + await prisma.sus.updateMany({ + where: { + userId: { + contains: userId, + }, + }, + data: { + active: false, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts new file mode 100644 index 0000000..410dd7f --- /dev/null +++ b/src/utils/database/verification.ts @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import type { GuildMember } from 'discord.js'; +import { PrismaClient } from '@prisma/client'; +import { updateUser } from './dbExistingUser'; +import { leaveBan } from '../verificationConfig'; +import { fibonacci } from '../mathsSeries'; + +export async function joinVerification(channelId: string, user: GuildMember) { + // Update the user on the database with the current roles they have + await updateUser(user); + + // Initialises Prisma Client + const prisma = new PrismaClient(); + + await prisma.verify.create({ + data: { + id: channelId, + user: { + connect: { + id: user.id, + }, + }, + }, + }); + + // Close database connection + await prisma.$disconnect(); +} + +export async function startVerification(channelId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + await prisma.verify.update({ + where: { + id: channelId, + }, + data: { + startTime: new Date(), + }, + }); + + // Close database connection + await prisma.$disconnect(); +} + +export async function getUser(channelId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Get the snowflake of the user verifying + const user = await prisma.verify.findUnique({ + where: { + id: channelId, + }, + select: { + userId: true, + }, + }); + + // Close database connection + await prisma.$disconnect(); + + // Check the user could be found + if (user === null) { + return null; + } + + // Return the user's snowflake + return user.userId; +} + +export async function finishVerification( + channelId: string, + verifierId: string, + info: { + page: number, + find: { + reason: number, + where: number + }, + length: number, + reasoning: number, + life: number, + food: number, + roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + } }, +) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // TODO potentially add an incomplete tracker? + await prisma.verify.update({ + where: { + id: channelId, + }, + data: { + verifier: { + connect: { + id: verifierId, + }, + }, + finishTime: new Date(), + // Roles + vegan: info.roles.vegan, + activist: info.roles.activist, + trusted: info.roles.trusted, + vegCurious: info.roles.vegCurious, + convinced: info.roles.convinced, + // Statistics + reason: info.find.reason, + where: info.find.where, + length: info.length, + reasoning: info.reasoning, + life: info.life, + food: info.food, + }, + }); + + // Close database connection + await prisma.$disconnect(); +} + +// Checks if verification was complete +export async function checkFinish(channelId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Get the snowflake of the user verifying + const finish = await prisma.verify.findUnique({ + where: { + id: channelId, + }, + select: { + finishTime: true, + }, + }); + + // Close database connection + await prisma.$disconnect(); + + // Checks if query returned is null + if (finish === null) { + return false; + } + + // Return if a finish time has been set meaning verification is complete + return finish.finishTime !== null; +} + +// Counts how many times the user has not had a verifier join their VC before leaving +export async function countIncomplete(userId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Count how many times the user has not completed a verification + const incompleteCount = await prisma.verify.count({ + where: { + userId, + finishTime: null, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + + return incompleteCount; +} + +// Gets the amount of time left on the block +export async function blockTime(userId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Count how many times the user has not completed a verification + const verification = await prisma.verify.findFirst({ + where: { + userId, + }, + orderBy: { + id: 'desc', + }, + }); + + // Close the database connection + await prisma.$disconnect(); + + if (verification === null) { + return 0; + } + + // If user finished verification + if (verification.finishTime !== null) { + // Activist role + if (verification.activist) { + return 0; + } + const timeOff = new Date().getTime() - verification.finishTime.getTime(); + return ((verification.vegan || verification.convinced) ? 604800000 : 1814400000) - timeOff; + } + + // Timeouts + const count = await countIncomplete(verification.userId) % (leaveBan + 1); + const timeOff = new Date().getTime() - verification.joinTime.getTime(); + // Creates the length of the time for the ban + return (fibonacci(count) * 3600_000) - timeOff; +} diff --git a/src/utils/dbExistingUser.ts b/src/utils/dbExistingUser.ts deleted file mode 100644 index 14a5892..0000000 --- a/src/utils/dbExistingUser.ts +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -/* - Animal Rights Advocates Discord Bot - Copyright (C) 2022 Anthony Berg - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -import type { GuildMember } from 'discord.js'; -import { PrismaClient } from '@prisma/client'; -import IDs from './ids'; - -// Checks if the user exists on the database -export async function userExists(user: GuildMember) { - // Initialises Prisma Client - const prisma = new PrismaClient(); - - // Counts if the user is on the database by their snowflake - const userQuery = await prisma.user.count({ - where: { - id: user.id, - }, - }); - - // Close the database connection - await prisma.$disconnect(); - - // If the user is found on the database, then return true, otherwise, false. - return userQuery > 0; -} - -// Adds the user to the database if they were already on the server before the bot/database -export async function addExistingUser(user: GuildMember) { - // Initialises Prisma Client - const prisma = new PrismaClient(); - - // Counts if the user is on the database by their snowflake - const userQuery = await prisma.user.count({ - where: { - id: user.id, - }, - }); - - // If the user is already in the database - if (userQuery > 0) { - return; - } - - // Checks what roles the user has - const hasVegan = user.roles.cache.has(IDs.roles.vegan.vegan); - const hasActivist = user.roles.cache.has(IDs.roles.vegan.activist); - const hasPlus = user.roles.cache.has(IDs.roles.vegan.plus); - const hasNotVegan = user.roles.cache.has(IDs.roles.nonvegan.nonvegan); - const hasVegCurious = user.roles.cache.has(IDs.roles.nonvegan.vegCurious); - const hasConvinced = user.roles.cache.has(IDs.roles.nonvegan.convinced); - const hasTrusted = user.roles.cache.has(IDs.roles.trusted); - const hasMuted = user.roles.cache.has(IDs.roles.restrictions.muted); - - // Create the user in the database - await prisma.user.create({ - data: { - id: user.id, - vegan: hasVegan, - trusted: hasTrusted, - activist: hasActivist, - plus: hasPlus, - notVegan: hasNotVegan, - vegCurious: hasVegCurious, - convinced: hasConvinced, - muted: hasMuted, - }, - }); - - // Close the database connection - await prisma.$disconnect(); -} diff --git a/src/utils/devIDs.ts b/src/utils/devIDs.ts index b5fb74b..72857b7 100644 --- a/src/utils/devIDs.ts +++ b/src/utils/devIDs.ts @@ -60,15 +60,28 @@ const devIDs = { channels: { information: { news: '999431676058927247', + conduct: '999431676058927248', + roles: '999431676058927250', }, staff: { coordinators: '999431676058927254', standup: '999431676289622183', verifiers: '999431677006860411', }, + dietSupport: { + info: '999431677006860417', + introduction: '999431677325615184', + main: '999431677325615185', + }, nonVegan: { general: '999431677325615189', }, + vegan: { + general: '999431677535338575', + }, + activism: { + activism: '999431678214807604', + }, diversity: { women: '999431679053660187', lgbtqia: '999431679053660188', diff --git a/src/utils/formatter.ts b/src/utils/formatter.ts new file mode 100644 index 0000000..5dc0664 --- /dev/null +++ b/src/utils/formatter.ts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +import type { Snowflake } from 'discord-api-types/globals'; + +export function rolesToString(roles: Snowflake[]) { + let output = ''; + + roles.forEach((role) => { + output += `<@&${role}>`; + }); + + if (output.length === 0) { + output = 'None'; + } + + return output; +} diff --git a/src/utils/ids.ts b/src/utils/ids.ts index c07074b..6d38d25 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -52,23 +52,39 @@ let IDs = { moderator: '826157475815489598', trialModerator: '982074555596152904', verifier: '871802735031373856', + trialVerifier: '982635638010572850', }, stageHost: '854893757593419786', patron: '765370219207852055', patreon: '993848684640997406', verifyingAsVegan: '854725899576279060', + verifyBlock: '1032765019269640203', }, channels: { information: { news: '866000393259319306', + conduct: '990728521531920385', + roles: '990761562199457813', }, staff: { coordinators: '1006240682505142354', standup: '996009201237233684', + verifiers: '873215538627756072', + }, + dietSupport: { + info: '993891104346873888', + introduction: '993272252743286874', + main: '822665615612837918', }, nonVegan: { general: '798967615636504657', }, + vegan: { + general: '787738272616808509', + }, + activism: { + activism: '730907954877956179', + }, diversity: { women: '938808963544285324', lgbtqia: '956224226556272670', @@ -77,6 +93,7 @@ let IDs = { }, }, categories: { + verification: '797505409073676299', diversity: '933078380394459146', }, }; diff --git a/src/utils/mathsSeries.ts b/src/utils/mathsSeries.ts new file mode 100644 index 0000000..2a99459 --- /dev/null +++ b/src/utils/mathsSeries.ts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +// Created because Stove loves Fibonacci sequences +// A fibonacci sequence where n = 0 => 1 +export function fibonacci(position: number) { + let previous = 0; + let next = 1; + let tempNext; + + for (let i = 0; i < position; i += 1) { + tempNext = next + previous; + previous = next; + next = tempNext; + } + + return next; +} diff --git a/src/utils/verificationConfig.ts b/src/utils/verificationConfig.ts new file mode 100644 index 0000000..c47e22e --- /dev/null +++ b/src/utils/verificationConfig.ts @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 Anthony Berg + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +// The maximum amount of verification VCs there can be +export const maxVCs = 10; + +// The maximum amount of leaving bans before time resets +export const leaveBan = 8; + +export const questionInfo = [ + { + question: 'Welcome to Animal Rights Advocates! How did you find the server?', + buttons: [ + 'Search', + 'Friend', + 'YouTube', + 'Another Server', + 'Vegan Org', + ], + }, + { + question: 'How long have you been vegan?', + buttons: [ + '<1 month', + '1-2 months', + '3-6 months', + '6 months - 1 year', + '1-2 years', + '2+ years', + ], + }, + { + question: 'Ask the user why they went vegan and to define veganism.\n' + + 'Do they cite ethical concerns and abstinence from at least meat, dairy, eggs, leather, and fur?', + buttons: [ + 'Yes', + 'Yes with prompting', + 'No', + ], + }, + { + question: 'Ask the user about their life as a vegan, including things like watching documentaries or social media content and interactions with family and friends. What are their stories like?', + buttons: [ + 'Believable', + 'Unbelievable', + 'Short', + ], + }, + { + question: 'Ask the user about food and nutrition. Do they seem to know how to live as a vegan?', + buttons: [ + 'Dietitian / Chef', + 'Acceptable', + 'Salads / Smoothies', + 'No clue', + ], + }, + { + question: 'Do you think this user is definitely vegan?', + buttons: [ + 'Yes', + 'No', + ], + }, + { + question: 'Offer to ask questions for Activist. Do you think they should get it?', + buttons: [ + 'Yes', + 'No', + ], + }, + { + question: 'Do some activism, asking Activist questions. Now which role should they get?', + buttons: [ + 'Vegan', + 'Convinced', + 'Non-vegan', + ], + }, + { + question: 'Should this user get Veg Curious?', + buttons: [ + 'Yes', + 'No', + ], + }, +]; + +export const serverFind = [ + // From a friend + { + question: 'Ask for username and indicate', + buttons: [ + 'Vegan', + 'Non-Vegan', + 'Unknown', + ], + }, + // From a video + { + question: 'Ask what video', + buttons: [ + 'Troll video', + 'Our content', + 'Other', + ], + }, + // From another server + { + question: 'Ask which server', + buttons: [ + 'Vegan', + 'Debate', + 'Other', + ], + }, + // From a vegan organisation + { + question: 'Ask which one', + buttons: [ + 'Vegan Hacktivists', + 'Other', + ], + }, +]; diff --git a/tsconfig.json b/tsconfig.json index e2256ed..659c12b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ @@ -101,7 +101,7 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + // "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, "include": ["src"] }