Compare commits
36 Commits
a68095ba90
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75a8e38f42 | ||
|
|
f7da37ffe3 | ||
|
|
4e461c3cff | ||
| 4d886df641 | |||
| fbb70a811c | |||
| 858fe33e62 | |||
| df4a978476 | |||
| 6e33467984 | |||
| 7bac005fe7 | |||
|
|
a9ea7bf8d5 | ||
|
|
580511b632 | ||
|
|
7bccab26eb | ||
|
|
e28b47c349 | ||
|
|
e21d5573b1 | ||
|
|
bc835922a5 | ||
|
|
d751db58f7 | ||
|
|
808785bb93 | ||
|
|
6d9bea9a6f | ||
|
|
e271f4b2df | ||
|
|
c7c0d9faab | ||
|
|
bb4c2e1ce4 | ||
| fb1ed3d46e | |||
| f668a91eb1 | |||
| 9b83148551 | |||
| 61a23df056 | |||
| 1e4167d942 | |||
| ecd9d59959 | |||
| 7315ca5c38 | |||
| 4ccdee79d7 | |||
| 8a7e396aed | |||
| 4091e700e5 | |||
|
|
e74f28bc1e | ||
|
|
2224105801 | ||
| fe4aea2202 | |||
|
|
514bc6d7b6 | ||
| fc21605138 |
55
.eslintrc.json
Normal file
55
.eslintrc.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/strict-boolean-expressions": [
|
||||
2,
|
||||
{
|
||||
"allowString" : false,
|
||||
"allowNumber" : false
|
||||
}
|
||||
],
|
||||
|
||||
/* important */
|
||||
"prefer-const": "error",
|
||||
"quotes": ["error", "single"],
|
||||
|
||||
"block-scoped-var": "error",
|
||||
"camelcase": "error",
|
||||
"consistent-this": ["error", "that"],
|
||||
"no-else-return": "error",
|
||||
"no-eq-null": "error",
|
||||
"no-floating-decimal": "error",
|
||||
"no-implicit-coercion": "error",
|
||||
"no-implied-eval": "error",
|
||||
"no-invalid-this": "error",
|
||||
"require-await": "error",
|
||||
"yoda": "error",
|
||||
|
||||
"semi": ["error", "always"],
|
||||
"semi-style": ["error", "last"],
|
||||
|
||||
/* less important */
|
||||
"no-unreachable-loop": "error",
|
||||
"no-unused-private-class-members": "error",
|
||||
"no-use-before-define": "error",
|
||||
"no-unmodified-loop-condition": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-promise-executor-return": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-constructor-return": "error",
|
||||
"no-template-curly-in-string": "error",
|
||||
"array-callback-return": "error",
|
||||
"no-eval": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-extra-bind": "error"
|
||||
},
|
||||
"ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"]
|
||||
}
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,2 +1,6 @@
|
||||
.DS_Store
|
||||
.vscode
|
||||
log
|
||||
dist
|
||||
node_modules
|
||||
token
|
||||
token.txt
|
||||
14
.pnpm-debug.log
Normal file
14
.pnpm-debug.log
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"0 debug pnpm:scope": {
|
||||
"selected": 1
|
||||
},
|
||||
"1 error pnpm": {
|
||||
"code": "ERR_PNPM_MISSING_PACKAGE_NAME",
|
||||
"err": {
|
||||
"name": "pnpm",
|
||||
"message": "`pnpm add` requires the package name",
|
||||
"code": "ERR_PNPM_MISSING_PACKAGE_NAME",
|
||||
"stack": "pnpm: `pnpm add` requires the package name\n at Object.handler [as add] (/Users/zomo/.nvm/versions/node/v17.1.0/lib/node_modules/pnpm/dist/pnpm.cjs:122191:15)\n at /Users/zomo/.nvm/versions/node/v17.1.0/lib/node_modules/pnpm/dist/pnpm.cjs:182192:83\n at async run (/Users/zomo/.nvm/versions/node/v17.1.0/lib/node_modules/pnpm/dist/pnpm.cjs:182168:34)\n at async runPnpm (/Users/zomo/.nvm/versions/node/v17.1.0/lib/node_modules/pnpm/dist/pnpm.cjs:182387:5)\n at async /Users/zomo/.nvm/versions/node/v17.1.0/lib/node_modules/pnpm/dist/pnpm.cjs:182379:7"
|
||||
}
|
||||
}
|
||||
}
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Ashley Rosch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
16
README.md
Normal file
16
README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# IKEA-Canada-Support
|
||||
|
||||
## running
|
||||
|
||||
| File | Description | Notes |
|
||||
| - | - | - |
|
||||
| `scripts/(os)/install` | installs the bot | must be ran again if you change the bot token |
|
||||
| `scripts/(os)/start` | starts the bot | includes a watchdog (so it automatically restarts if it crashes) |
|
||||
|
||||
## dev
|
||||
|
||||
| Command | Description |
|
||||
| - | - |
|
||||
| `npm run build` | builds the bot and registers the commands |
|
||||
| `npm run start` | starts the bot |
|
||||
| `npm run dev` OR `npm run watch` | watches for changes, then builds and starts the bot |
|
||||
24
build.mjs
Normal file
24
build.mjs
Normal file
@@ -0,0 +1,24 @@
|
||||
import { build } from 'esbuild';
|
||||
import commandLineArgs from 'command-line-args';
|
||||
|
||||
const args = commandLineArgs([
|
||||
{ name: 'watch', alias: 'w', type: Boolean },
|
||||
{ name: 'bundle', alias: 'b', type: Boolean },
|
||||
{ name: 'minify', alias: 'm', type: Boolean },
|
||||
{ name: 'sourcemap', alias: 's', type: Boolean }
|
||||
]);
|
||||
|
||||
//build TS
|
||||
build({
|
||||
entryPoints: ['src/main.ts'],
|
||||
outdir: 'dist',
|
||||
|
||||
target: 'es2020',
|
||||
platform: 'node',
|
||||
format: 'cjs',
|
||||
|
||||
watch: args.watch,
|
||||
bundle: args.bundle,
|
||||
minify: args.minify,
|
||||
sourcemap: args.sourcemap
|
||||
});
|
||||
337
package-lock.json
generated
337
package-lock.json
generated
@@ -1,337 +0,0 @@
|
||||
{
|
||||
"name": "ikea-canada-support",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ikea-canada-support",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.3.1",
|
||||
"discord-buttons": "github:ZomoXYZ/discord-buttons",
|
||||
"discord.js": "^12.5.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/collection": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
|
||||
"integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@discordjs/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.1.tgz",
|
||||
"integrity": "sha512-N87VuQi7HEeRJkhzovao/JviiqKjDKMVKxKMfUvSKw+MbkbW8R0nA3fi/MQhhlxV2fQ+2ReM+/Nt4efdrJx3zA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.5"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/discord-buttons": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "git+ssh://git@github.com/ZomoXYZ/discord-buttons.git#a61689454f33b5fd456057546d7cd83bbb48b1cd",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://ko-fi.com/angelocore"
|
||||
}
|
||||
},
|
||||
"node_modules/discord.js": {
|
||||
"version": "12.5.3",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
|
||||
"integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@discordjs/collection": "^0.1.6",
|
||||
"@discordjs/form-data": "^3.0.1",
|
||||
"abort-controller": "^3.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"prism-media": "^1.2.9",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"ws": "^7.4.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.48.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.31",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"mime-db": "1.48.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prism-media": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.1.tgz",
|
||||
"integrity": "sha512-nyYAa3KB4qteJIqdguKmwxTJgy55xxUtkJ3uRnOvO5jO+frci+9zpRXw6QZVcfDeva3S654fU9+26P2OSTzjHw==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"@discordjs/opus": "^0.5.0",
|
||||
"ffmpeg-static": "^4.2.7 || ^3.0.0 || ^2.4.0",
|
||||
"node-opus": "^0.3.3",
|
||||
"opusscript": "^0.0.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@discordjs/opus": {
|
||||
"optional": true
|
||||
},
|
||||
"ffmpeg-static": {
|
||||
"optional": true
|
||||
},
|
||||
"node-opus": {
|
||||
"optional": true
|
||||
},
|
||||
"opusscript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz",
|
||||
"integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@discordjs/collection": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
|
||||
"integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@discordjs/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "16.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.1.tgz",
|
||||
"integrity": "sha512-N87VuQi7HEeRJkhzovao/JviiqKjDKMVKxKMfUvSKw+MbkbW8R0nA3fi/MQhhlxV2fQ+2ReM+/Nt4efdrJx3zA==",
|
||||
"dev": true
|
||||
},
|
||||
"abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||
"dev": true
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"dev": true
|
||||
},
|
||||
"discord-buttons": {
|
||||
"version": "git+ssh://git@github.com/ZomoXYZ/discord-buttons.git#a61689454f33b5fd456057546d7cd83bbb48b1cd",
|
||||
"dev": true,
|
||||
"from": "discord-buttons@github:ZomoXYZ/discord-buttons"
|
||||
},
|
||||
"discord.js": {
|
||||
"version": "12.5.3",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
|
||||
"integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@discordjs/collection": "^0.1.6",
|
||||
"@discordjs/form-data": "^3.0.1",
|
||||
"abort-controller": "^3.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"prism-media": "^1.2.9",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"ws": "^7.4.4"
|
||||
}
|
||||
},
|
||||
"event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.48.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.31",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mime-db": "1.48.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
|
||||
"dev": true
|
||||
},
|
||||
"prism-media": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.1.tgz",
|
||||
"integrity": "sha512-nyYAa3KB4qteJIqdguKmwxTJgy55xxUtkJ3uRnOvO5jO+frci+9zpRXw6QZVcfDeva3S654fU9+26P2OSTzjHw==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
|
||||
"dev": true
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||
"dev": true
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz",
|
||||
"integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
package.json
48
package.json
@@ -4,9 +4,51 @@
|
||||
"type": "git",
|
||||
"url": "git@git.zomo.dev:zomo/IKEA-Canada-Support.git"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "dist/main.js",
|
||||
"scripts": {
|
||||
"build": "node ./build.mjs -bs",
|
||||
"start": "node .",
|
||||
"watch": "npm-watch",
|
||||
"dev": "npm-watch",
|
||||
"getname": "echo $npm_package_name"
|
||||
},
|
||||
"watch": {
|
||||
"build": {
|
||||
"patterns": [
|
||||
"src"
|
||||
],
|
||||
"extensions": "ts",
|
||||
"legacyWatch": true
|
||||
},
|
||||
"start": {
|
||||
"patterns": [
|
||||
"dist"
|
||||
],
|
||||
"extensions": "js",
|
||||
"legacyWatch": true,
|
||||
"runOnChangeOnly": true
|
||||
}
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.3.1",
|
||||
"discord-buttons": "github:ZomoXYZ/discord-buttons",
|
||||
"discord.js": "^12.5.3"
|
||||
"@discordjs/rest": "^0.3.0",
|
||||
"@types/command-line-args": "^5.2.0",
|
||||
"@types/node": "^17.0.23",
|
||||
"@typescript-eslint/eslint-plugin": "^5.17.0",
|
||||
"@typescript-eslint/parser": "^5.17.0",
|
||||
"command-line-args": "^5.2.1",
|
||||
"esbuild": "^0.14.29",
|
||||
"eslint": "^8.12.0",
|
||||
"npm-watch": "^0.11.0",
|
||||
"ts-node": "^10.7.0",
|
||||
"typescript": "^4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"discord.js": "^13.6.0",
|
||||
"discordslash": "github:zomoxyz/discordslash",
|
||||
"lang": "github:zomoxyz/lang"
|
||||
}
|
||||
}
|
||||
|
||||
2030
pnpm-lock.yaml
generated
Normal file
2030
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,324 +0,0 @@
|
||||
import { MessageActionRow, MessageButton, MessageButtonStyleResolvable, MessageComponent, MessageMenu, MessageMenuOption } from 'discord-buttons';
|
||||
import { Message, TextChannel } from 'discord.js';
|
||||
const Discord = require('discord.js'),
|
||||
client = new Discord.Client({ ws: { intents: Discord.Intents.ALL } }),
|
||||
disbut = require('discord-buttons');
|
||||
disbut(client);
|
||||
|
||||
client.on('ready', () => {
|
||||
console.log('ready')
|
||||
})
|
||||
|
||||
declare interface OptMenuOptions {
|
||||
label: string;
|
||||
emoji?: string;
|
||||
val: string;
|
||||
desc?: string;
|
||||
roleid: string;
|
||||
default?: boolean;
|
||||
}
|
||||
|
||||
declare interface OptMenu {
|
||||
type: 'menu';
|
||||
message: string;
|
||||
palceholder: string;
|
||||
id: string;
|
||||
max: number|'all';
|
||||
options: OptMenuOptions[];
|
||||
}
|
||||
|
||||
declare interface OptRowButton {
|
||||
style: MessageButtonStyleResolvable;
|
||||
label: string;
|
||||
id: string;
|
||||
roleid: string;
|
||||
}
|
||||
|
||||
declare interface OptRow {
|
||||
type: 'row';
|
||||
message: string;
|
||||
buttons: [OptRowButton?, OptRowButton?, OptRowButton?, OptRowButton?, OptRowButton?];
|
||||
}
|
||||
|
||||
const InteractionRoles: (OptRow|OptMenu)[] = [
|
||||
{
|
||||
type: 'menu',
|
||||
message: 'Pronouns',
|
||||
palceholder: '',
|
||||
id: 'rolemenu',
|
||||
max: 'all',
|
||||
options: [
|
||||
{
|
||||
label: 'They/Them',
|
||||
val: 'they',
|
||||
roleid: '861453442387279872'
|
||||
},
|
||||
{
|
||||
label: 'He/Him',
|
||||
val: 'he',
|
||||
roleid: '861453443188129872'
|
||||
},
|
||||
{
|
||||
label: 'She/Her',
|
||||
val: 'she',
|
||||
roleid: '861453442777219112'
|
||||
},
|
||||
{
|
||||
label: 'It/Its',
|
||||
val: 'it',
|
||||
roleid: '862687464543223809'
|
||||
},
|
||||
{
|
||||
label: 'Fae/Faer',
|
||||
val: 'fae',
|
||||
roleid: '862687559464386601'
|
||||
},
|
||||
{
|
||||
label: 'Any',
|
||||
val: 'any',
|
||||
roleid: '861453441422983169'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'menu',
|
||||
message: 'Role Color',
|
||||
palceholder: '',
|
||||
id: 'colormenu',
|
||||
max: 1,
|
||||
options: [
|
||||
{
|
||||
label: 'red',
|
||||
val: 'red',
|
||||
roleid: '863621755774959626'
|
||||
},
|
||||
{
|
||||
label: 'pink',
|
||||
val: 'pink',
|
||||
roleid: '863621801191931904'
|
||||
},
|
||||
{
|
||||
label: 'orange',
|
||||
val: 'orange',
|
||||
roleid: '863621849153273876'
|
||||
},
|
||||
{
|
||||
label: 'green',
|
||||
val: 'green',
|
||||
roleid: '863621885366894592'
|
||||
},
|
||||
{
|
||||
label: 'mint green',
|
||||
val: 'mint green',
|
||||
roleid: '863622000512860190'
|
||||
},
|
||||
{
|
||||
label: 'blue',
|
||||
val: 'blue',
|
||||
roleid: '863622336573079603'
|
||||
},
|
||||
{
|
||||
label: 'light blue',
|
||||
val: 'light blue',
|
||||
roleid: '863622365316513793'
|
||||
},
|
||||
{
|
||||
label: 'periwinkle',
|
||||
val: 'periwinkle',
|
||||
roleid: '863622403775266816'
|
||||
},
|
||||
{
|
||||
label: 'purple',
|
||||
val: 'purple',
|
||||
roleid: '863622442790682674'
|
||||
},
|
||||
{
|
||||
label: 'blank',
|
||||
val: 'blank',
|
||||
roleid: '',
|
||||
default: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'menu',
|
||||
message: 'Other Roles',
|
||||
palceholder: '',
|
||||
id: 'otherrolesmenu',
|
||||
max: 'all',
|
||||
options: [
|
||||
{
|
||||
label: 'Movie Night',
|
||||
val: 'movie',
|
||||
roleid: '862883242436591617'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
function sendMenu(c: TextChannel, menuOpts: OptMenu) {
|
||||
|
||||
let select = new MessageMenu()
|
||||
.setID(menuOpts.id)
|
||||
.setPlaceholder(menuOpts.palceholder)
|
||||
.setMaxValues(menuOpts.max === 'all' ? menuOpts.options.length : menuOpts.max)
|
||||
.setMinValues(0);
|
||||
|
||||
for (let i = 0; i < menuOpts.options.length; i++) {
|
||||
|
||||
let opts: OptMenuOptions = menuOpts.options[i];
|
||||
|
||||
let option = new MessageMenuOption()
|
||||
.setLabel(opts.label)
|
||||
.setValue(opts.val);
|
||||
|
||||
if (opts.emoji && opts.emoji.length)
|
||||
option.setEmoji(opts.emoji);
|
||||
|
||||
if (opts.desc && opts.desc.length)
|
||||
option.setDescription(opts.desc);
|
||||
|
||||
if (opts.default)
|
||||
option.setDefault();
|
||||
|
||||
select.addOption(option);
|
||||
|
||||
}
|
||||
|
||||
c.send(menuOpts.message, select);
|
||||
}
|
||||
|
||||
function sendRow(c: TextChannel, rowOpts: OptRow) {
|
||||
|
||||
let row = new MessageActionRow();
|
||||
|
||||
for (let i = 0; i < rowOpts.buttons.length; i++) {
|
||||
|
||||
let opts: OptRowButton = rowOpts.buttons[i];
|
||||
|
||||
let option = new MessageButton()
|
||||
.setStyle(opts.style)
|
||||
.setLabel(opts.label)
|
||||
.setID(opts.id);
|
||||
|
||||
row.addComponent(option);
|
||||
|
||||
}
|
||||
|
||||
c.send(rowOpts.message, row);
|
||||
}
|
||||
|
||||
client.on('message', (m: Message) => {
|
||||
|
||||
if (m.author.id === '167336999844315137' && m.content === '.') {
|
||||
|
||||
for (let i = 0; i < InteractionRoles.length; i++) {
|
||||
switch (InteractionRoles[i].type) {
|
||||
case 'menu':
|
||||
sendMenu(m.channel as TextChannel, InteractionRoles[i] as OptMenu);
|
||||
break;
|
||||
case 'row':
|
||||
sendRow(m.channel as TextChannel, InteractionRoles[i] as OptRow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
const xor = (v1: boolean, v2: boolean) => (v1 || v2) && !(v1 && v2);
|
||||
|
||||
client.on('clickMenu', (menu: MessageComponent) => {
|
||||
menu.reply.think(true).then(async () => {
|
||||
|
||||
let menus = InteractionRoles.filter(opt => opt.type === 'menu' && opt.id === menu.id);
|
||||
|
||||
if (menus.length) {
|
||||
let m = menus[0] as OptMenu,
|
||||
vals = menu.values || [];
|
||||
|
||||
let changed: {
|
||||
add: string[],
|
||||
rem: string[]
|
||||
} = {
|
||||
add: [],
|
||||
rem: []
|
||||
}
|
||||
|
||||
console.log(vals);
|
||||
|
||||
for (let i = 0; i < m.options.length; i++) {
|
||||
|
||||
let opt = m.options[i],
|
||||
{roleid} = opt;
|
||||
|
||||
if (roleid) {
|
||||
|
||||
let role = await menu.guild.roles.fetch(roleid);
|
||||
|
||||
let names = []
|
||||
menu.clicker.member.roles.cache.forEach(r => names.push(r.name));
|
||||
let hasrole = menu.clicker.member.roles.cache.some(r => r.id === role.id),
|
||||
needsrole = vals && vals.includes(opt.val);
|
||||
|
||||
console.log(role.name, `[${names.join()}]`, needsrole, hasrole)
|
||||
|
||||
if (vals && vals.includes(opt.val) && !menu.clicker.member.roles.cache.some(r => r.id === role.id)) {
|
||||
await menu.clicker.member.roles.add(role);
|
||||
changed.add.push(role.name);
|
||||
} else if (menu.clicker.member.roles.cache.some(r => r.id === role.id)) {
|
||||
await menu.clicker.member.roles.remove(role);
|
||||
changed.rem.push(role.name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
console.log('\n');
|
||||
|
||||
let message = [];
|
||||
|
||||
if (changed.add.length)
|
||||
message.push(`Added \`${changed.add.join(', ')}\``);
|
||||
|
||||
if (changed.rem.length)
|
||||
message.push(`Removed \`${changed.rem.join(', ')}\``);
|
||||
|
||||
menu.reply.edit(message.join('\n'));
|
||||
|
||||
} else
|
||||
menu.reply.edit('Error: Unknown menu');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
client.on('clickButton', (button: MessageComponent) => {
|
||||
button.reply.think(true).then(async () => {
|
||||
|
||||
let rows = InteractionRoles.filter(opt => opt.type === 'row');
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
let row = rows[i] as OptRow;
|
||||
let matchingButtons = row.buttons.filter(opt => opt.id === button.id);
|
||||
|
||||
if (matchingButtons.length) {
|
||||
|
||||
let role = await button.guild.roles.fetch(matchingButtons[0].roleid);
|
||||
|
||||
if (button.clicker.member.roles.cache.some(r => r.id === role.id)) {
|
||||
await button.clicker.member.roles.remove(role.id);
|
||||
button.reply.edit(`Added \`${role.name}\``);
|
||||
} else {
|
||||
await button.clicker.member.roles.remove(role.id);
|
||||
button.reply.edit(`Removed \`${role.name}\``);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
client.login(require('fs').readFileSync('../token').toString());
|
||||
293
rolemanager/package-lock.json
generated
293
rolemanager/package-lock.json
generated
@@ -1,293 +0,0 @@
|
||||
{
|
||||
"name": "rolemanager",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"discord-buttons": "github:ZomoXYZ/discord-buttons",
|
||||
"discord.js": "^12.5.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/collection": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
|
||||
"integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="
|
||||
},
|
||||
"node_modules/@discordjs/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"dependencies": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.5"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/discord-buttons": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "git+ssh://git@github.com/ZomoXYZ/discord-buttons.git#a61689454f33b5fd456057546d7cd83bbb48b1cd",
|
||||
"license": "Apache-2.0",
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://ko-fi.com/angelocore"
|
||||
}
|
||||
},
|
||||
"node_modules/discord.js": {
|
||||
"version": "12.5.3",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
|
||||
"integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
|
||||
"dependencies": {
|
||||
"@discordjs/collection": "^0.1.6",
|
||||
"@discordjs/form-data": "^3.0.1",
|
||||
"abort-controller": "^3.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"prism-media": "^1.2.9",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"ws": "^7.4.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.48.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.31",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.48.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prism-media": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.1.tgz",
|
||||
"integrity": "sha512-nyYAa3KB4qteJIqdguKmwxTJgy55xxUtkJ3uRnOvO5jO+frci+9zpRXw6QZVcfDeva3S654fU9+26P2OSTzjHw==",
|
||||
"peerDependencies": {
|
||||
"@discordjs/opus": "^0.5.0",
|
||||
"ffmpeg-static": "^4.2.7 || ^3.0.0 || ^2.4.0",
|
||||
"node-opus": "^0.3.3",
|
||||
"opusscript": "^0.0.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@discordjs/opus": {
|
||||
"optional": true
|
||||
},
|
||||
"ffmpeg-static": {
|
||||
"optional": true
|
||||
},
|
||||
"node-opus": {
|
||||
"optional": true
|
||||
},
|
||||
"opusscript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.2.tgz",
|
||||
"integrity": "sha512-lkF7AWRicoB9mAgjeKbGqVUekLnSNO4VjKVnuPHpQeOxZOErX6BPXwJk70nFslRCEEA8EVW7ZjKwXaP9N+1sKQ==",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@discordjs/collection": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
|
||||
"integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="
|
||||
},
|
||||
"@discordjs/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"requires": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"discord-buttons": {
|
||||
"version": "git+ssh://git@github.com/ZomoXYZ/discord-buttons.git#a61689454f33b5fd456057546d7cd83bbb48b1cd",
|
||||
"from": "discord-buttons@github:ZomoXYZ/discord-buttons"
|
||||
},
|
||||
"discord.js": {
|
||||
"version": "12.5.3",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
|
||||
"integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
|
||||
"requires": {
|
||||
"@discordjs/collection": "^0.1.6",
|
||||
"@discordjs/form-data": "^3.0.1",
|
||||
"abort-controller": "^3.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"prism-media": "^1.2.9",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"ws": "^7.4.4"
|
||||
}
|
||||
},
|
||||
"event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.48.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
|
||||
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.31",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
|
||||
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
|
||||
"requires": {
|
||||
"mime-db": "1.48.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
},
|
||||
"prism-media": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.1.tgz",
|
||||
"integrity": "sha512-nyYAa3KB4qteJIqdguKmwxTJgy55xxUtkJ3uRnOvO5jO+frci+9zpRXw6QZVcfDeva3S654fU9+26P2OSTzjHw==",
|
||||
"requires": {}
|
||||
},
|
||||
"setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.2.tgz",
|
||||
"integrity": "sha512-lkF7AWRicoB9mAgjeKbGqVUekLnSNO4VjKVnuPHpQeOxZOErX6BPXwJk70nFslRCEEA8EVW7ZjKwXaP9N+1sKQ==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"name": "rolemanager",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"start": "ts-node .",
|
||||
"build": "tsc .",
|
||||
"start-node": "node ."
|
||||
}
|
||||
}
|
||||
19
scripts/mac-linux/install
Executable file
19
scripts/mac-linux/install
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
#change to ccurrent directory
|
||||
cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
|
||||
cd ../..
|
||||
|
||||
#discord token
|
||||
[ ! -f "token.txt" ] && touch "token.txt"
|
||||
|
||||
if [ ! -s "token.txt" ]
|
||||
then
|
||||
printf "Enter your discord bot token: "
|
||||
read token
|
||||
printf $token > "token.txt"
|
||||
fi
|
||||
|
||||
#run
|
||||
npm install
|
||||
npm run build
|
||||
42
scripts/mac-linux/start
Executable file
42
scripts/mac-linux/start
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
#change to current directory
|
||||
cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
|
||||
cd ../..
|
||||
|
||||
#colors
|
||||
C1='\033[1;37m'
|
||||
C2='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
#make log folder
|
||||
if [[ ! -d log ]]
|
||||
then
|
||||
mkdir log
|
||||
fi
|
||||
|
||||
#current file number
|
||||
num=0
|
||||
if [[ -f log/number ]]
|
||||
then
|
||||
num=$(cat log/number)
|
||||
fi
|
||||
|
||||
echo $num > log/number
|
||||
|
||||
#watchdog
|
||||
while true
|
||||
do
|
||||
|
||||
#increment log file number
|
||||
num=$(( num + 1 ))
|
||||
echo $num > log/number
|
||||
|
||||
#run
|
||||
npm start 2> log/$num.err | tee log/$num.out
|
||||
|
||||
#give chance to close program
|
||||
printf "\n\n\n${C1}press ${C2}Control+C${C1} to close${NC}\n\n\n"
|
||||
sleep 5
|
||||
|
||||
done
|
||||
12
scripts/mac-linux/start_screen
Executable file
12
scripts/mac-linux/start_screen
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
#change to ccurrent directory
|
||||
cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
|
||||
|
||||
#start
|
||||
if [[ $(screen -ls | grep $(npm run getname -s)) ]]; then
|
||||
echo "Session already exists"
|
||||
else
|
||||
screen -S $(npm run getname -s) -d -m ./start
|
||||
echo "Created session"
|
||||
fi
|
||||
12
scripts/mac-linux/start_tmux
Executable file
12
scripts/mac-linux/start_tmux
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
#change to ccurrent directory
|
||||
cd -- "$( dirname -- "${BASH_SOURCE[0]}" )"
|
||||
|
||||
#start
|
||||
if [[ $(tmux ls | grep $(npm run getname -s)) ]]; then
|
||||
echo "Session already exists"
|
||||
else
|
||||
tmux new-session -d -s $(npm run getname -s) ./start
|
||||
echo "Created session"
|
||||
fi
|
||||
17
scripts/windows/install.bat
Normal file
17
scripts/windows/install.bat
Normal file
@@ -0,0 +1,17 @@
|
||||
@echo off
|
||||
|
||||
@REM change to ccurrent directory
|
||||
cd %~f0\..\..\..\
|
||||
|
||||
@REM discord token
|
||||
if not exist "token.txt" copy NUL "token.txt"
|
||||
|
||||
for /f %%i in ("token.txt") do set size=%%~zi
|
||||
if %size% equ 0 (
|
||||
set /p token="Enter your discord bot token: "
|
||||
echo | set /p=%id% > "token.txt"
|
||||
)
|
||||
|
||||
@REM run
|
||||
npm install
|
||||
npm run build
|
||||
28
scripts/windows/start.bat
Normal file
28
scripts/windows/start.bat
Normal file
@@ -0,0 +1,28 @@
|
||||
@echo off
|
||||
|
||||
@Rem change to current directory
|
||||
cd %~f0\..\..\..\
|
||||
|
||||
@Rem make log folder
|
||||
if not exist log mkdir log
|
||||
|
||||
@Rem current file number
|
||||
set /A num=0
|
||||
if exist log\number set /p num=<log\number
|
||||
|
||||
echo %num > log\number
|
||||
|
||||
@Rem watchdog
|
||||
:watchdog
|
||||
|
||||
@Rem increment log file number
|
||||
set /A num=num+1
|
||||
echo %num > log\number
|
||||
|
||||
@Rem run
|
||||
powershell "npm start 2> log\%num%.err | tee log\%num%.out"
|
||||
|
||||
@Rem give chance to close program
|
||||
timeout /t 5 /nobreak
|
||||
|
||||
goto watchdog
|
||||
69
src/lang.ts
Normal file
69
src/lang.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import Lang, { setLang } from "lang";
|
||||
import { setEmsgShim } from "discordslash";
|
||||
|
||||
export default function() {
|
||||
|
||||
setLang({
|
||||
|
||||
main: {
|
||||
login: 'Logged in as {user}'
|
||||
},
|
||||
|
||||
command: {
|
||||
|
||||
ping: {
|
||||
embed: true,
|
||||
title: 'Pong!',
|
||||
description: [
|
||||
'Woah!',
|
||||
'This descriptions has multiple lines'
|
||||
],
|
||||
color: '#a0cc75',
|
||||
timestamp: true,
|
||||
footer: {
|
||||
text: '{username}',
|
||||
iconURL: '{avatar}'
|
||||
}
|
||||
},
|
||||
|
||||
roles: {
|
||||
description: {
|
||||
command: 'displays the role selections',
|
||||
category: 'the category of roles that will be displayed'
|
||||
}
|
||||
},
|
||||
rolesall: {
|
||||
description: {
|
||||
command: 'displays the role selections for everyone',
|
||||
category: 'the category of roles that will be displayed',
|
||||
channel: 'the channel the message(s) will be sent in'
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
error: {
|
||||
|
||||
main: {
|
||||
missingToken: 'Missing Discord Token, please enter the bot token into the token file'
|
||||
},
|
||||
|
||||
general: {
|
||||
noUser: 'Unable to retrieve guild user information, please try again',
|
||||
noMember: 'Unable to retrieve guild member information, please try again',
|
||||
noChannel: 'Unable to retrieve text channel information, please try again'
|
||||
},
|
||||
|
||||
interaction: {
|
||||
noid: 'Interaction ID not found',
|
||||
norole: 'No role found from interaction'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
setEmsgShim(Lang)
|
||||
|
||||
}
|
||||
33
src/main.ts
Normal file
33
src/main.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Client, Intents } from 'discord.js';
|
||||
import { initClient } from 'discordslash';
|
||||
import Lang from 'lang';
|
||||
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
||||
import SetLang from './lang';
|
||||
import { initRolemanager } from './rolemanager';
|
||||
|
||||
//init logs with a timestamp
|
||||
console.log(new Date().toISOString()+'\n\n');
|
||||
|
||||
SetLang();
|
||||
|
||||
//get token
|
||||
if (!existsSync('./token.txt')) {
|
||||
writeFileSync('./token.txt', '');
|
||||
console.error(Lang.get('error.main.missingToken'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const TOKEN = readFileSync('./token.txt').toString(),
|
||||
CLIENT = new Client({ intents: [Intents.FLAGS.GUILDS] });
|
||||
|
||||
initClient(CLIENT);
|
||||
initRolemanager(CLIENT);
|
||||
|
||||
//discord connections
|
||||
CLIENT.on('ready', client => {
|
||||
console.log(Lang.get('main.login', {
|
||||
user: client.user.tag
|
||||
}));
|
||||
});
|
||||
|
||||
CLIENT.login(TOKEN);
|
||||
38
src/rolemanager/commands.ts
Normal file
38
src/rolemanager/commands.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { CommandInteraction, TextChannel } from "discord.js";
|
||||
import { InteractionRoles } from "./data";
|
||||
import { sendRoles } from "../util/interactions";
|
||||
|
||||
export function RolesCommand(interaction: CommandInteraction) {
|
||||
let category = interaction.options.getInteger('category', true);
|
||||
sendRoles(interaction, InteractionRoles[category].id, true);
|
||||
}
|
||||
|
||||
export async function RolesAllCommand(interaction: CommandInteraction) {
|
||||
if (interaction.user.id === '167336999844315137') {
|
||||
|
||||
let givenChannel = interaction.options.getChannel('channel'),
|
||||
channel: TextChannel = await interaction.client.channels.fetch(interaction.channelId) as TextChannel;
|
||||
|
||||
if (givenChannel && givenChannel.type === 'GUILD_TEXT')
|
||||
channel = givenChannel as TextChannel;
|
||||
|
||||
if (channel) {
|
||||
let category = interaction.options.getInteger('category');
|
||||
sendRoles(channel, category ? InteractionRoles[category].id : undefined);
|
||||
interaction.reply({
|
||||
content: `sending message in <#${channel.id}>`,
|
||||
ephemeral: true
|
||||
})
|
||||
|
||||
} else
|
||||
interaction.reply({
|
||||
content: 'error finding channel to send message in',
|
||||
ephemeral: true
|
||||
})
|
||||
|
||||
} else
|
||||
interaction.reply({
|
||||
content: 'missing permissions',
|
||||
ephemeral: true
|
||||
})
|
||||
}
|
||||
136
src/rolemanager/data.ts
Normal file
136
src/rolemanager/data.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import * as Opt from "../types/Opt";
|
||||
|
||||
//array of Opt.Row|Opt.Menu, each one is a message that will be sent/understood
|
||||
// - types/Opt.d.ts
|
||||
export const InteractionRoles: (Opt.Row|Opt.Menu)[] = [
|
||||
{
|
||||
type: 'menu',
|
||||
message: 'Pronouns',
|
||||
palceholder: '',
|
||||
id: 'pronounsmenu',
|
||||
max: 'all',
|
||||
options: [
|
||||
{
|
||||
label: 'They/Them',
|
||||
value: 'they',
|
||||
roleid: '861453442387279872'
|
||||
},
|
||||
{
|
||||
label: 'He/Him',
|
||||
value: 'he',
|
||||
roleid: '861453443188129872'
|
||||
},
|
||||
{
|
||||
label: 'She/Her',
|
||||
value: 'she',
|
||||
roleid: '861453442777219112'
|
||||
},
|
||||
{
|
||||
label: 'It/Its',
|
||||
value: 'it',
|
||||
roleid: '862687464543223809'
|
||||
},
|
||||
{
|
||||
label: 'Fae/Faer',
|
||||
value: 'faefaer',
|
||||
roleid: '862687559464386601'
|
||||
},
|
||||
{
|
||||
label: 'Fae/Fem',
|
||||
value: 'faefem',
|
||||
roleid: '985215761796694106'
|
||||
},
|
||||
{
|
||||
label: 'Any',
|
||||
value: 'any',
|
||||
roleid: '861453441422983169'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'menu',
|
||||
message: 'Role Color',
|
||||
palceholder: '',
|
||||
id: 'colormenu',
|
||||
max: 1,
|
||||
options: [
|
||||
{
|
||||
label: 'red',
|
||||
value: 'red',
|
||||
roleid: '863621755774959626'
|
||||
},
|
||||
{
|
||||
label: 'pink',
|
||||
value: 'pink',
|
||||
roleid: '863621801191931904'
|
||||
},
|
||||
{
|
||||
label: 'orange',
|
||||
value: 'orange',
|
||||
roleid: '863621849153273876'
|
||||
},
|
||||
{
|
||||
label: 'green',
|
||||
value: 'green',
|
||||
roleid: '863621885366894592'
|
||||
},
|
||||
{
|
||||
label: 'mint green',
|
||||
value: 'mint green',
|
||||
roleid: '863622000512860190'
|
||||
},
|
||||
{
|
||||
label: 'blue',
|
||||
value: 'blue',
|
||||
roleid: '863622336573079603'
|
||||
},
|
||||
{
|
||||
label: 'light blue',
|
||||
value: 'light blue',
|
||||
roleid: '863622365316513793'
|
||||
},
|
||||
{
|
||||
label: 'periwinkle',
|
||||
value: 'periwinkle',
|
||||
roleid: '863622403775266816'
|
||||
},
|
||||
{
|
||||
label: 'purple',
|
||||
value: 'purple',
|
||||
roleid: '863622442790682674'
|
||||
},
|
||||
{
|
||||
label: 'blank',
|
||||
value: 'blank',
|
||||
roleid: '',
|
||||
default: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'menu',
|
||||
message: 'Other Roles',
|
||||
palceholder: '',
|
||||
id: 'rolesmenu',
|
||||
max: 'all',
|
||||
options: [
|
||||
{
|
||||
label: 'Movie Night',
|
||||
value: 'movie',
|
||||
roleid: '862883242436591617'
|
||||
},
|
||||
{
|
||||
label: 'Dungeons and Dragons',
|
||||
value: 'dnd',
|
||||
roleid: '872684620666265602'
|
||||
},
|
||||
{
|
||||
label: 'VR Haver',
|
||||
value: 'vr',
|
||||
roleid: '927020684918534195'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const GuildId = '861404201645244416';
|
||||
186
src/rolemanager/index.ts
Normal file
186
src/rolemanager/index.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
import { ButtonInteraction, Client, GuildMember, Interaction, MessageButton, MessageSelectMenu, SelectMenuInteraction } from "discord.js";
|
||||
import { emsg } from "discordslash";
|
||||
import * as Opt from "../types/Opt";
|
||||
import { getGuild, getMember } from "../util/discord";
|
||||
|
||||
import { InteractionRoles } from "./data";
|
||||
import { initSlash } from "./slash";
|
||||
|
||||
export function initRolemanager(client: Client) {
|
||||
|
||||
initSlash();
|
||||
|
||||
//on interaction event
|
||||
client.on('interactionCreate', (interaction: Interaction) => {
|
||||
|
||||
if (!interaction.inGuild()) return;
|
||||
|
||||
try {
|
||||
|
||||
if (interaction.isSelectMenu())
|
||||
handleSelect(interaction as SelectMenuInteraction);
|
||||
|
||||
else if (interaction.isButton())
|
||||
handleButton(interaction as ButtonInteraction);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.error(e);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async function handleButton(interaction: ButtonInteraction) {
|
||||
|
||||
//start typing
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
//get custom id
|
||||
let customId: string;
|
||||
if (interaction.component instanceof MessageButton && interaction.component.customId !== null)
|
||||
customId = interaction.component.customId;
|
||||
else if ('custom_id' in interaction.component)
|
||||
customId = interaction.component.custom_id;
|
||||
else
|
||||
throw emsg('interaction.noid');
|
||||
|
||||
//list of button rows from data
|
||||
let rows = InteractionRoles.filter(opt => opt.type === 'row');
|
||||
|
||||
//loop through each the buttons rows
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
|
||||
let row = rows[i] as Opt.Row;
|
||||
|
||||
//filter to just buttons with matching id
|
||||
let matchingButtons = row.buttons.filter(opt => opt && opt.id === customId) as Opt.RowButton[];
|
||||
|
||||
if (matchingButtons.length) {
|
||||
|
||||
let member = getMember(interaction);
|
||||
|
||||
//if there's no role id, then nothing can be done
|
||||
if (matchingButtons[0].roleid) {
|
||||
|
||||
//get corresponding role
|
||||
let role = await getGuild(interaction).roles.fetch(matchingButtons[0].roleid);
|
||||
|
||||
if (role === null)
|
||||
throw emsg('interaction.norole');
|
||||
|
||||
//if clicker (member) does have the role
|
||||
//TODO why do i need role !== null here
|
||||
if (member.roles.cache.some(r => role !== null && r.id === role.id)) {
|
||||
|
||||
//remove role
|
||||
await member.roles.remove(role.id);
|
||||
interaction.editReply(`Removed \`${role.name}\``);
|
||||
|
||||
} else {
|
||||
|
||||
//add role
|
||||
await member.roles.add(role.id);
|
||||
interaction.editReply(`Added \`${role.name}\``);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//on menu click
|
||||
async function handleSelect(interaction: SelectMenuInteraction) {
|
||||
|
||||
//start typing
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
//get custom id
|
||||
let customId: string;
|
||||
if (interaction.component instanceof MessageSelectMenu && interaction.component.customId !== null)
|
||||
customId = interaction.component.customId;
|
||||
else if ('custom_id' in interaction.component)
|
||||
customId = interaction.component.custom_id;
|
||||
|
||||
//list of menus from data with matching id
|
||||
let menus = InteractionRoles.filter(opt => opt.type === 'menu' && opt.id === customId);
|
||||
|
||||
if (menus.length) {
|
||||
|
||||
//use first menu with matching id
|
||||
let m = menus[0] as Opt.Menu,
|
||||
vals = interaction.values || [];
|
||||
|
||||
//list of changes
|
||||
let changed: {
|
||||
add: string[],
|
||||
rem: string[]
|
||||
} = {
|
||||
add: [],
|
||||
rem: []
|
||||
};
|
||||
|
||||
//loop through all the options in the menu
|
||||
for (let i = 0; i < m.options.length; i++) {
|
||||
|
||||
let opt: Opt.MenuOptions = m.options[i],
|
||||
{roleid} = opt;
|
||||
|
||||
//if there's no role id, then nothing can be done
|
||||
if (roleid && interaction.member instanceof GuildMember) {
|
||||
|
||||
//since it is a GuildMember, let's force typescript to rememeber it
|
||||
let member = getMember(interaction);
|
||||
|
||||
//get corresponding role
|
||||
let role = await getGuild(interaction).roles.fetch(roleid);
|
||||
|
||||
if (role === null)
|
||||
throw emsg('interaction.norole');
|
||||
|
||||
//if enabled
|
||||
if (vals && vals.includes(opt.value)) {
|
||||
|
||||
//if member doesn't have the role
|
||||
if (!member.roles.cache.some(r => role !== null && r.id === role.id)) {
|
||||
|
||||
//give role
|
||||
await member.roles.add(role);
|
||||
changed.add.push(role.name);
|
||||
|
||||
}
|
||||
|
||||
//else if member does have the role
|
||||
} else if (member.roles.cache.some(r => role !== null && r.id === role.id)) {
|
||||
|
||||
//remove role
|
||||
await member.roles.remove(role);
|
||||
changed.rem.push(role.name);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//convert changes to a message
|
||||
let message = [];
|
||||
|
||||
if (changed.add.length)
|
||||
message.push(`Added \`${changed.add.join(', ')}\``);
|
||||
|
||||
if (changed.rem.length)
|
||||
message.push(`Removed \`${changed.rem.join(', ')}\``);
|
||||
|
||||
interaction.editReply(message.length ? message.join('\n') : 'No Changes');
|
||||
|
||||
} else
|
||||
interaction.editReply('Error: Unknown menu');
|
||||
|
||||
};
|
||||
52
src/rolemanager/slash.ts
Normal file
52
src/rolemanager/slash.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { addCommand, CommandGenerator, CommandOptionGenerator, OptionChoices } from 'discordslash';
|
||||
import { InteractionRoles } from './data';
|
||||
import Lang from 'lang';
|
||||
import { RolesAllCommand, RolesCommand } from './commands';
|
||||
|
||||
export function initSlash() {
|
||||
|
||||
const Categories: OptionChoices[] = InteractionRoles.map(opt => ({
|
||||
name: opt.message,
|
||||
value: opt.id
|
||||
}));
|
||||
|
||||
addCommand([
|
||||
|
||||
//roles ======
|
||||
new CommandGenerator()
|
||||
.setName('roles')
|
||||
.setDescription(Lang.get('command.roles.description.command'))
|
||||
.addOption([
|
||||
|
||||
new CommandOptionGenerator()
|
||||
.setName('category')
|
||||
.setType('string')
|
||||
.setDescription(Lang.get('commands.roles.categorydescription.category'))
|
||||
.addChoice(Categories)
|
||||
.setRequired()
|
||||
|
||||
])
|
||||
.setRun(RolesCommand),
|
||||
|
||||
//rolesall ======
|
||||
new CommandGenerator()
|
||||
.setName('rolesall')
|
||||
.setDescription(Lang.get('command.rolesall.description.command'))
|
||||
.addOption([
|
||||
|
||||
new CommandOptionGenerator()
|
||||
.setName('category')
|
||||
.setType('string')
|
||||
.setDescription(Lang.get('command.rolesall.description.category'))
|
||||
.addChoice(Categories),
|
||||
|
||||
new CommandOptionGenerator()
|
||||
.setName('channel')
|
||||
.setType('channel')
|
||||
.setDescription(Lang.get('command.rolesall.description.command'))
|
||||
|
||||
])
|
||||
.setRun(RolesAllCommand)
|
||||
|
||||
]);
|
||||
}
|
||||
35
src/types/Opt.d.ts
vendored
Normal file
35
src/types/Opt.d.ts
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import { MessageButtonStyleResolvable } from 'discord.js';
|
||||
|
||||
//menu
|
||||
export interface MenuOptions {
|
||||
label: string;
|
||||
emoji?: string;
|
||||
value: string;
|
||||
description?: string;
|
||||
roleid: string;
|
||||
default?: boolean;
|
||||
}
|
||||
|
||||
export interface Menu {
|
||||
type: 'menu';
|
||||
message: string;
|
||||
palceholder: string;
|
||||
id: string;
|
||||
max: number|'all';
|
||||
options: MenuOptions[];
|
||||
}
|
||||
|
||||
//row
|
||||
export interface RowButton {
|
||||
style: MessageButtonStyleResolvable;
|
||||
label: string;
|
||||
id: string;
|
||||
roleid: string;
|
||||
}
|
||||
|
||||
export interface Row {
|
||||
type: 'row';
|
||||
message: string;
|
||||
id: string; //not needed for api, just needed for slash commands
|
||||
buttons: [RowButton?, RowButton?, RowButton?, RowButton?, RowButton?];
|
||||
}
|
||||
58
src/util/discord.ts
Normal file
58
src/util/discord.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { ButtonInteraction, CommandInteraction, Guild, GuildMember, SelectMenuInteraction, TextChannel, User } from 'discord.js';
|
||||
import { emsg } from 'discordslash';
|
||||
|
||||
export type ReplyableInteraction = ButtonInteraction | CommandInteraction | SelectMenuInteraction;
|
||||
|
||||
export const isReplyableInteraction = (res: any): boolean => res instanceof ButtonInteraction || res instanceof CommandInteraction || res instanceof SelectMenuInteraction;
|
||||
|
||||
/**
|
||||
* get the User of an interaction
|
||||
* @throws errorMessage class if it cannot be read
|
||||
*/
|
||||
export function getUser(interaction: ReplyableInteraction): User {
|
||||
const user = interaction.user;
|
||||
|
||||
if (!(user instanceof User))
|
||||
throw emsg('general.noUser');
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the GuildMember of an interaction
|
||||
* @throws errorMessage class if it cannot be read
|
||||
*/
|
||||
export function getMember(interaction: ReplyableInteraction): GuildMember {
|
||||
const member = interaction.member;
|
||||
|
||||
if (!(member instanceof GuildMember))
|
||||
throw emsg('general.noMember');
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the TextChannel of an interaction
|
||||
* @throws errorMessage class if it cannot be read
|
||||
*/
|
||||
export function getChannel(interaction: ReplyableInteraction): TextChannel {
|
||||
const channel = interaction.channel;
|
||||
|
||||
if (!(channel instanceof TextChannel))
|
||||
throw emsg('general.noChannel');
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the TextChannel of an interaction
|
||||
* @throws errorMessage class if it cannot be read
|
||||
*/
|
||||
export function getGuild(interaction: ReplyableInteraction): Guild {
|
||||
const guild = interaction.guild;
|
||||
|
||||
if (!(guild instanceof Guild))
|
||||
throw emsg('general.noGuild');
|
||||
|
||||
return guild;
|
||||
}
|
||||
148
src/util/interactions.ts
Normal file
148
src/util/interactions.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { MessageActionRow, MessageButton, MessageSelectMenu, MessageSelectOptionData, TextBasedChannel } from "discord.js";
|
||||
import { InteractionRoles } from "../rolemanager/data";
|
||||
import * as Opt from "../types/Opt";
|
||||
import { isReplyableInteraction, ReplyableInteraction } from "./discord";
|
||||
|
||||
export const sendMessage = (res: ReplyableInteraction | TextBasedChannel, msg: any, ephemeral?: boolean) => {
|
||||
|
||||
let arg: any = {};
|
||||
if (typeof msg === 'object')
|
||||
arg = msg;
|
||||
else
|
||||
arg.content = msg;
|
||||
|
||||
if (isReplyableInteraction(res) && ephemeral)
|
||||
arg.ephemeral = true;
|
||||
|
||||
if (isReplyableInteraction(res))
|
||||
(res as ReplyableInteraction).reply(arg);
|
||||
else
|
||||
(res as TextBasedChannel).send(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* send message containing menu
|
||||
* @param res text channel to send message or interaction to reply to
|
||||
* @param menuOpts menu data object
|
||||
*/
|
||||
function sendMenu(res: ReplyableInteraction|TextBasedChannel, menuOpts: Opt.Menu, ephemeral?: boolean) {
|
||||
|
||||
let row = new MessageActionRow()
|
||||
|
||||
let select = new MessageSelectMenu()
|
||||
.setCustomId(menuOpts.id)
|
||||
.setPlaceholder(menuOpts.palceholder)
|
||||
.setMaxValues(menuOpts.max === 'all' ? menuOpts.options.length : menuOpts.max)
|
||||
.setMinValues(0);
|
||||
|
||||
let options: MessageSelectOptionData[] = [];
|
||||
|
||||
for (let i = 0; i < menuOpts.options.length; i++) {
|
||||
|
||||
let opts: Opt.MenuOptions = menuOpts.options[i];
|
||||
|
||||
let option: MessageSelectOptionData = {
|
||||
label: opts.label,
|
||||
value: opts.value
|
||||
};
|
||||
|
||||
if (opts.emoji && opts.emoji.length)
|
||||
option.emoji = opts.emoji;
|
||||
|
||||
if (opts.description && opts.description.length)
|
||||
option.description = opts.description;
|
||||
|
||||
if (opts.default)
|
||||
option.default = true;
|
||||
|
||||
options.push(option);
|
||||
|
||||
}
|
||||
|
||||
select.addOptions(options);
|
||||
row.addComponents(select)
|
||||
|
||||
let arg = {
|
||||
content: menuOpts.message,
|
||||
components: [row]
|
||||
};
|
||||
|
||||
sendMessage(res, arg, ephemeral);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* send message containing row
|
||||
* @param res text channel to send message
|
||||
* @param rowOpts row data object
|
||||
*/
|
||||
function sendRow(res: ReplyableInteraction|TextBasedChannel, rowOpts: Opt.Row, ephemeral?: boolean) {
|
||||
|
||||
let row = new MessageActionRow();
|
||||
|
||||
let options: MessageButton[] = [];
|
||||
|
||||
for (let i = 0; i < rowOpts.buttons.length; i++) {
|
||||
|
||||
let opts = rowOpts.buttons[i];
|
||||
|
||||
if (opts) {
|
||||
let option = new MessageButton()
|
||||
.setStyle(opts.style)
|
||||
.setLabel(opts.label)
|
||||
.setCustomId(opts.id);
|
||||
|
||||
options.push(option);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
row.addComponents(options);
|
||||
|
||||
let arg = {
|
||||
content: rowOpts.message,
|
||||
components: [row]
|
||||
};
|
||||
|
||||
sendMessage(res, arg, ephemeral);
|
||||
|
||||
}
|
||||
|
||||
export async function sendRoles(res: ReplyableInteraction|TextBasedChannel, id?: string, ephemeral?: boolean) {
|
||||
|
||||
if (id) {
|
||||
|
||||
let rowarr = InteractionRoles.filter(r => r.id === id);
|
||||
if (rowarr.length) {
|
||||
|
||||
let row = rowarr[0];
|
||||
|
||||
if (row.type === 'menu')
|
||||
sendMenu(res, row as Opt.Menu, ephemeral);
|
||||
else if (row.type === 'row')
|
||||
sendRow(res, row as Opt.Row, ephemeral);
|
||||
|
||||
} else
|
||||
sendMessage(res, `invalid id ${id}`, ephemeral);
|
||||
|
||||
} else if (isReplyableInteraction(res))
|
||||
sendMessage(res, `missing id`, ephemeral);
|
||||
|
||||
else {
|
||||
|
||||
for (let i = 0; i < InteractionRoles.length; i++) {
|
||||
|
||||
switch (InteractionRoles[i].type) {
|
||||
case 'menu':
|
||||
sendMenu(res, InteractionRoles[i] as Opt.Menu, ephemeral);
|
||||
break;
|
||||
case 'row':
|
||||
sendRow(res, InteractionRoles[i] as Opt.Row, ephemeral);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
21
tsconfig.json
Normal file
21
tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"module": "commonjs",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"typeRoots": [
|
||||
"./src/types/"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user