mirror of
https://github.com/Hessenuk/DiscordTickets.git
synced 2024-12-23 08:13:09 +02:00
* feat: make command handler slash command-ready Only `help` and `settings` commands work so far * feat(commands): finish new settings command * fix(settings): convert `roles` and `ping` to an array * fix(commands): make `add` a slash command * fix(commands): make `blacklist` a slash command * fix(commands): remove URLs from `help` command * Add weblate badge and overview image * Update sponsors * sqlite things * imrpovements * update eslint rules * (⚠ untested) close command * fix: default locale for getting command option names * Update README.md * Update README.md * Update README.md * update new command to slash commands and fix close command * fixes and improvements * fix: closing a ticket when the creator has left * Revert "fix: closing a ticket when the creator has left" This reverts commit afc40ae17077782e344fd8cee03a089966c2347e. * fix: closing a ticket when the creator has left * fix: localisation issues in settings command * fix: delete category channel * New button and select panels + updated message panels Includes new options for panel embed message image and thumbnail Co-Authored-By: Puneet Gopinath <baalkrshna@gmail.com> Co-Authored-By: thevisuales <6569806+thevisuales@users.noreply.github.com> * Finish converting to buttons, added close button Co-Authored-By: Puneet Gopinath <baalkrshna@gmail.com> Co-Authored-By: thevisuales <6569806+thevisuales@users.noreply.github.com> * fully convert to slash commands * re-add "... has created a ticket" message * locales * fix add and remove commands * fix remove command * fix stats command * eslint Co-authored-by: Puneet Gopinath <baalkrshna@gmail.com> Co-authored-by: thevisuales <6569806+thevisuales@users.noreply.github.com>
This commit is contained in:
parent
39e2cef38d
commit
95f76716ed
@ -100,7 +100,8 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
'max-lines': [
|
'max-lines': [
|
||||||
'warn'
|
'warn',
|
||||||
|
500
|
||||||
],
|
],
|
||||||
'max-statements-per-line': [
|
'max-statements-per-line': [
|
||||||
'error'
|
'error'
|
||||||
|
14
README.md
14
README.md
@ -1,9 +1,11 @@
|
|||||||
[![GitHub stars](https://img.shields.io/github/stars/discord-tickets/bot?style=flat-square)](https://github.com/discord-tickets/bot/stargazers)
|
[![GitHub stars](https://img.shields.io/github/stars/discord-tickets/bot?style=flat-square)](https://github.com/discord-tickets/bot/stargazers)
|
||||||
[![GitHub forks](https://img.shields.io/github/forks/discord-tickets/bot?style=flat-square)](https://github.com/discord-tickets/bot/stargazers)
|
[![GitHub forks](https://img.shields.io/github/forks/discord-tickets/bot?style=flat-square)](https://github.com/discord-tickets/bot/stargazers)
|
||||||
[![License](https://img.shields.io/github/license/discord-tickets/bot?style=flat-square)](https://github.com/discord-tickets/bot/blob/main/LICENSE)
|
[![License](https://img.shields.io/github/license/discord-tickets/bot?style=flat-square)](https://github.com/discord-tickets/bot/blob/main/LICENSE)
|
||||||
|
![](https://img.shields.io/badge/dynamic/json?color=5865F2&label=bots&query=clients&url=https%3A%2F%2Fstats.discordtickets.app&logo=discord&logoColor=white&style=flat-square)
|
||||||
|
![](https://img.shields.io/badge/dynamic/json?color=5865F2&label=tickets&query=tickets&url=https%3A%2F%2Fstats.discordtickets.app&logo=discord&logoColor=white&style=flat-square)
|
||||||
[![Codacy](https://img.shields.io/codacy/grade/b974eb5f984c40868e07d82c968bd02d?logo=codacy&style=flat-square)](https://www.codacy.com/gh/discord-tickets/bot/dashboard?utm_source=github.com&utm_medium=referral&utm_content=discord-tickets/bot&utm_campaign=Badge_Grade)
|
[![Codacy](https://img.shields.io/codacy/grade/b974eb5f984c40868e07d82c968bd02d?logo=codacy&style=flat-square)](https://www.codacy.com/gh/discord-tickets/bot/dashboard?utm_source=github.com&utm_medium=referral&utm_content=discord-tickets/bot&utm_campaign=Badge_Grade)
|
||||||
[![Discord](https://img.shields.io/discord/451745464480432129?label=discord&color=7289DA&style=flat-square)](https://go.eartharoid.me/discord)
|
[![Discord](https://img.shields.io/discord/451745464480432129?label=discord&color=7289DA&style=flat-square)](https://go.eartharoid.me/discord)
|
||||||
[![Crowdin](https://badges.crowdin.net/discord-tickets/localized.svg)](https://i18n.discordtickets.app/project/discord-tickets)
|
[![Weblate](https://i18n.capestar.net/widgets/discord-tickets/en_GB/bot/svg-badge.svg)](https://i18n.capestar.net/engage/discord-tickets/en_GB/)
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@ -37,6 +39,8 @@ You can also configure the functionality of the bot to your liking and add comma
|
|||||||
If the bot hasn't already been translated to your (community's) language, you can [translate](https://github.com/discord-tickets/.github/blob/main//CONTRIBUTING.md#translating) it yourself.
|
If the bot hasn't already been translated to your (community's) language, you can [translate](https://github.com/discord-tickets/.github/blob/main//CONTRIBUTING.md#translating) it yourself.
|
||||||
Plugin authors are encouraged to support multiple languages as well.
|
Plugin authors are encouraged to support multiple languages as well.
|
||||||
|
|
||||||
|
[![Weblate](https://i18n.capestar.net/widgets/discord-tickets/en_GB/bot/multi-auto.svg)](https://i18n.capestar.net/engage/discord-tickets/en_GB/)
|
||||||
|
|
||||||
3. **Multiple ticket categories**
|
3. **Multiple ticket categories**
|
||||||
Each ticket category has its own settings for messages and the support team roles. There's also multiple methods of creating a ticket.
|
Each ticket category has its own settings for messages and the support team roles. There's also multiple methods of creating a ticket.
|
||||||
|
|
||||||
@ -88,7 +92,13 @@ Thank you to everyone to has contributed to Discord Tickets, including everyone
|
|||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
Does your community or company use Discord Tickets? Sponsor the project to get your logo shown here.
|
*Does your community or company use Discord Tickets? [Sponsor the project](https://github.com/discord-tickets/bot/?sponsor=1) to get your logo shown here.*
|
||||||
|
|
||||||
|
**These awesome people and communities sponsor Discord Tickets:**
|
||||||
|
|
||||||
|
- [reSkybounds](https://reskybounds.com/) ([Discord](https://discord.reskybounds.com/))
|
||||||
|
- [Cal#0004](https://discord.com/users/239036926152146944) <!-- @24c4 -->
|
||||||
|
|
||||||
|
|
||||||
### Donate
|
### Donate
|
||||||
|
|
||||||
|
18
package.json
18
package.json
@ -33,22 +33,18 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eartharoid/i18n": "^1.0.0",
|
"@eartharoid/i18n": "^1.0.0",
|
||||||
"boxen": "^5.0.1",
|
"boxen": "^5.0.1",
|
||||||
"command-line-args": "^5.2.0",
|
|
||||||
"cryptr": "^6.0.2",
|
"cryptr": "^6.0.2",
|
||||||
"discord.js": "^13.1.0",
|
"discord.js": "^13.1.0",
|
||||||
"dotenv": "^8.6.0",
|
"dotenv": "^8.6.0",
|
||||||
"jsonschema": "^1.4.0",
|
|
||||||
"keyv": "^4.0.3",
|
"keyv": "^4.0.3",
|
||||||
"leeks.js": "^0.2.2",
|
"leeks.js": "^0.2.2",
|
||||||
"leekslazylogger": "^3.0.2",
|
"leekslazylogger": "^3.0.2",
|
||||||
|
"ms": "^2.1.3",
|
||||||
"mustache": "^4.2.0",
|
"mustache": "^4.2.0",
|
||||||
"node-emoji": "^1.11.0",
|
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
"sequelize": "^6.6.5",
|
"sequelize": "^6.6.5",
|
||||||
"string-argv": "^0.3.1",
|
"terminal-link": "^2.1.1"
|
||||||
"terminal-link": "^2.1.1",
|
|
||||||
"to-time-monthsfork": "^1.1.4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"all-contributors-cli": "^6.20.0",
|
"all-contributors-cli": "^6.20.0",
|
||||||
@ -64,10 +60,10 @@
|
|||||||
"sqlite3": "^5.0.2"
|
"sqlite3": "^5.0.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"mariadb": "^2.5.2",
|
"mariadb": "^2.5.4",
|
||||||
"mysql2": "^2.2.5",
|
"mysql2": "^2.3.0",
|
||||||
"pg": "^8.5.1",
|
"pg": "^8.7.1",
|
||||||
"pg-hstore": "^2.3.3",
|
"pg-hstore": "^2.3.4",
|
||||||
"tedious": "^11.0.3"
|
"tedious": "^11.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,17 @@ specifiers:
|
|||||||
'@eartharoid/i18n': ^1.0.0
|
'@eartharoid/i18n': ^1.0.0
|
||||||
all-contributors-cli: ^6.20.0
|
all-contributors-cli: ^6.20.0
|
||||||
boxen: ^5.0.1
|
boxen: ^5.0.1
|
||||||
command-line-args: ^5.2.0
|
|
||||||
cryptr: ^6.0.2
|
cryptr: ^6.0.2
|
||||||
discord.js: ^13.1.0
|
discord.js: ^13.1.0
|
||||||
dotenv: ^8.6.0
|
dotenv: ^8.6.0
|
||||||
eslint: ^7.32.0
|
eslint: ^7.32.0
|
||||||
jsonschema: ^1.4.0
|
|
||||||
keyv: ^4.0.3
|
keyv: ^4.0.3
|
||||||
leeks.js: ^0.2.2
|
leeks.js: ^0.2.2
|
||||||
leekslazylogger: ^3.0.2
|
leekslazylogger: ^3.0.2
|
||||||
mariadb: ^2.5.4
|
mariadb: ^2.5.4
|
||||||
|
ms: ^2.1.3
|
||||||
mustache: ^4.2.0
|
mustache: ^4.2.0
|
||||||
mysql2: ^2.3.0
|
mysql2: ^2.3.0
|
||||||
node-emoji: ^1.11.0
|
|
||||||
node-fetch: ^2.6.1
|
node-fetch: ^2.6.1
|
||||||
nodemon: ^2.0.12
|
nodemon: ^2.0.12
|
||||||
pg: ^8.7.1
|
pg: ^8.7.1
|
||||||
@ -24,30 +22,24 @@ specifiers:
|
|||||||
semver: ^7.3.5
|
semver: ^7.3.5
|
||||||
sequelize: ^6.6.5
|
sequelize: ^6.6.5
|
||||||
sqlite3: ^5.0.2
|
sqlite3: ^5.0.2
|
||||||
string-argv: ^0.3.1
|
|
||||||
tedious: ^11.4.0
|
tedious: ^11.4.0
|
||||||
terminal-link: ^2.1.1
|
terminal-link: ^2.1.1
|
||||||
to-time-monthsfork: ^1.1.4
|
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eartharoid/i18n': 1.0.0
|
'@eartharoid/i18n': 1.0.0
|
||||||
boxen: 5.0.1
|
boxen: 5.0.1
|
||||||
command-line-args: 5.2.0
|
|
||||||
cryptr: 6.0.2
|
cryptr: 6.0.2
|
||||||
discord.js: 13.1.0
|
discord.js: 13.1.0
|
||||||
dotenv: 8.6.0
|
dotenv: 8.6.0
|
||||||
jsonschema: 1.4.0
|
|
||||||
keyv: 4.0.3
|
keyv: 4.0.3
|
||||||
leeks.js: 0.2.2
|
leeks.js: 0.2.2
|
||||||
leekslazylogger: 3.0.2
|
leekslazylogger: 3.0.2
|
||||||
|
ms: 2.1.3
|
||||||
mustache: 4.2.0
|
mustache: 4.2.0
|
||||||
node-emoji: 1.11.0
|
|
||||||
node-fetch: 2.6.1
|
node-fetch: 2.6.1
|
||||||
semver: 7.3.5
|
semver: 7.3.5
|
||||||
sequelize: 6.6.5_aa1b3c7f5b5df187fb1a5c6073dca637
|
sequelize: 6.6.5_aa1b3c7f5b5df187fb1a5c6073dca637
|
||||||
string-argv: 0.3.1
|
|
||||||
terminal-link: 2.1.1
|
terminal-link: 2.1.1
|
||||||
to-time-monthsfork: 1.1.4
|
|
||||||
|
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
sqlite3: 5.0.2
|
sqlite3: 5.0.2
|
||||||
@ -591,11 +583,6 @@ packages:
|
|||||||
sprintf-js: 1.0.3
|
sprintf-js: 1.0.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/array-back/3.1.0:
|
|
||||||
resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/asn1/0.2.4:
|
/asn1/0.2.4:
|
||||||
resolution: {integrity: sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==}
|
resolution: {integrity: sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -659,10 +646,6 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/bignumber.js/2.4.0:
|
|
||||||
resolution: {integrity: sha1-g4qZLan51zfg9LLbC+YrsJ3Qxeg=}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/binary-extensions/2.2.0:
|
/binary-extensions/2.2.0:
|
||||||
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -908,16 +891,6 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
|
|
||||||
/command-line-args/5.2.0:
|
|
||||||
resolution: {integrity: sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==}
|
|
||||||
engines: {node: '>=4.0.0'}
|
|
||||||
dependencies:
|
|
||||||
array-back: 3.1.0
|
|
||||||
find-replace: 3.0.0
|
|
||||||
lodash.camelcase: 4.3.0
|
|
||||||
typical: 4.0.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/concat-map/0.0.1:
|
/concat-map/0.0.1:
|
||||||
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
|
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
|
||||||
|
|
||||||
@ -1343,13 +1316,6 @@ packages:
|
|||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/find-replace/3.0.0:
|
|
||||||
resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==}
|
|
||||||
engines: {node: '>=4.0.0'}
|
|
||||||
dependencies:
|
|
||||||
array-back: 3.1.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/find-up/4.1.0:
|
/find-up/4.1.0:
|
||||||
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -1903,10 +1869,6 @@ packages:
|
|||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/jsonschema/1.4.0:
|
|
||||||
resolution: {integrity: sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/jsonwebtoken/8.5.1:
|
/jsonwebtoken/8.5.1:
|
||||||
resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==}
|
resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==}
|
||||||
engines: {node: '>=4', npm: '>=1.4.28'}
|
engines: {node: '>=4', npm: '>=1.4.28'}
|
||||||
@ -2019,10 +1981,6 @@ packages:
|
|||||||
p-locate: 4.1.0
|
p-locate: 4.1.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/lodash.camelcase/4.3.0:
|
|
||||||
resolution: {integrity: sha1-soqmKIorn8ZRA1x3EfZathkDMaY=}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/lodash.clonedeep/4.5.0:
|
/lodash.clonedeep/4.5.0:
|
||||||
resolution: {integrity: sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=}
|
resolution: {integrity: sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=}
|
||||||
dev: true
|
dev: true
|
||||||
@ -2273,12 +2231,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
|
resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==}
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/node-emoji/1.11.0:
|
|
||||||
resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==}
|
|
||||||
dependencies:
|
|
||||||
lodash: 4.17.21
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/node-fetch/2.6.1:
|
/node-fetch/2.6.1:
|
||||||
resolution: {integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==}
|
resolution: {integrity: sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==}
|
||||||
engines: {node: 4.x || >=6.0.0}
|
engines: {node: 4.x || >=6.0.0}
|
||||||
@ -3102,11 +3054,6 @@ packages:
|
|||||||
engines: {node: '>=4', npm: '>=6'}
|
engines: {node: '>=4', npm: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/string-argv/0.3.1:
|
|
||||||
resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==}
|
|
||||||
engines: {node: '>=0.6.19'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/string-width/1.0.2:
|
/string-width/1.0.2:
|
||||||
resolution: {integrity: sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=}
|
resolution: {integrity: sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -3314,13 +3261,6 @@ packages:
|
|||||||
is-number: 7.0.0
|
is-number: 7.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/to-time-monthsfork/1.1.4:
|
|
||||||
resolution: {integrity: sha512-3bWuIwm9QeOAq/UClxFp86QMSJ4GVHmAT8X+pkM0mIMVrpJPLfSieY5qvSsfLJugLNWTVpYJ2ayKWXH3jcAdow==}
|
|
||||||
engines: {node: '>=4.6'}
|
|
||||||
dependencies:
|
|
||||||
bignumber.js: 2.4.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/toposort-class/1.0.1:
|
/toposort-class/1.0.1:
|
||||||
resolution: {integrity: sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=}
|
resolution: {integrity: sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=}
|
||||||
dev: false
|
dev: false
|
||||||
@ -3417,11 +3357,6 @@ packages:
|
|||||||
is-typedarray: 1.0.0
|
is-typedarray: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/typical/4.0.0:
|
|
||||||
resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/undefsafe/2.0.3:
|
/undefsafe/2.0.3:
|
||||||
resolution: {integrity: sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==}
|
resolution: {integrity: sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
MessageEmbed
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
|
|
||||||
@ -8,111 +8,111 @@ module.exports = class AddCommand extends Command {
|
|||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
description: i18n('commands.add.args.member.description'),
|
|
||||||
example: i18n('commands.add.args.member.example'),
|
|
||||||
name: i18n('commands.add.args.member.name'),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: i18n('commands.add.args.ticket.description'),
|
|
||||||
example: i18n('commands.add.args.ticket.example'),
|
|
||||||
name: i18n('commands.add.args.ticket.name'),
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.add.description'),
|
description: i18n('commands.add.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.add.name'),
|
name: i18n('commands.add.name'),
|
||||||
process_args: false
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.add.options.member.description'),
|
||||||
|
name: i18n('commands.add.options.member.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.USER
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.add.options.ticket.description'),
|
||||||
|
name: i18n('commands.add.options.ticket.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.CHANNEL
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message, args) {
|
async execute(interaction) {
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
|
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
const ticket = message.mentions.channels.first() ?? message.channel;
|
const channel = interaction.options.getChannel(default_i18n('commands.add.options.ticket.name')) ?? interaction.channel;
|
||||||
const t_row = await this.client.tickets.resolve(ticket.id, message.guild.id);
|
const t_row = await this.client.tickets.resolve(channel.id, interaction.guild.id);
|
||||||
|
|
||||||
if (!t_row) {
|
if (!t_row) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.add.response.not_a_ticket.title'))
|
.setTitle(i18n('commands.add.response.not_a_ticket.title'))
|
||||||
.setDescription(i18n('commands.add.response.not_a_ticket.description'))
|
.setDescription(i18n('commands.add.response.not_a_ticket.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const member = message.mentions.members.first() ?? message.guild.members.cache.get(args);
|
const member = interaction.options.getMember(default_i18n('commands.add.options.member.name'));
|
||||||
|
|
||||||
if (!member) {
|
if (!member) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.add.response.no_member.title'))
|
.setTitle(i18n('commands.add.response.no_member.title'))
|
||||||
.setDescription(i18n('commands.add.response.no_member.description'))
|
.setDescription(i18n('commands.add.response.no_member.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t_row.creator !== message.author.id && !await this.client.utils.isStaff(message.member)) {
|
if (t_row.creator !== interaction.member.id && !await this.client.utils.isStaff(interaction.member)) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.add.response.no_permission.title'))
|
.setTitle(i18n('commands.add.response.no_permission.title'))
|
||||||
.setDescription(i18n('commands.add.response.no_permission.description'))
|
.setDescription(i18n('commands.add.response.no_permission.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.channel.id !== ticket.id) {
|
await interaction.reply({
|
||||||
await message.channel.send({
|
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.success_colour)
|
.setColor(settings.success_colour)
|
||||||
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.add.response.added.title'))
|
.setTitle(i18n('commands.add.response.added.title'))
|
||||||
.setDescription(i18n('commands.add.response.added.description', member.toString(), ticket.toString()))
|
.setDescription(i18n('commands.add.response.added.description', member.toString(), channel.toString()))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
await ticket.send({
|
await channel.send({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
||||||
.setTitle(i18n('ticket.member_added.title'))
|
.setTitle(i18n('ticket.member_added.title'))
|
||||||
.setDescription(i18n('ticket.member_added.description', member.toString(), message.author.toString()))
|
.setDescription(i18n('ticket.member_added.description', member.toString(), interaction.user.toString()))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
await ticket.permissionOverwrites.edit(member, {
|
await channel.permissionOverwrites.edit(member, {
|
||||||
ATTACH_FILES: true,
|
ATTACH_FILES: true,
|
||||||
READ_MESSAGE_HISTORY: true,
|
READ_MESSAGE_HISTORY: true,
|
||||||
SEND_MESSAGES: true,
|
SEND_MESSAGES: true,
|
||||||
VIEW_CHANNEL: true
|
VIEW_CHANNEL: true
|
||||||
}, `${message.author.tag} added ${member.user.tag} to the ticket`);
|
}, `${interaction.user.tag} added ${member.user.tag} to the ticket`);
|
||||||
|
|
||||||
await this.client.tickets.archives.updateMember(ticket.id, member);
|
await this.client.tickets.archives.updateMember(channel.id, member);
|
||||||
|
|
||||||
this.client.log.info(`${message.author.tag} added ${member.user.tag} to ${ticket.id}`);
|
this.client.log.info(`${interaction.user.tag} added ${member.user.tag} to ${channel.id}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,125 +1,156 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
MessageEmbed,
|
||||||
|
Role
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
|
|
||||||
module.exports = class BlacklistCommand extends Command {
|
module.exports = class BlacklistCommand extends Command {
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [
|
|
||||||
i18n('commands.blacklist.aliases.unblacklist')
|
|
||||||
],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
description: i18n('commands.blacklist.args.member_or_role.description'),
|
|
||||||
example: i18n('commands.blacklist.args.member_or_role.example'),
|
|
||||||
name: i18n('commands.blacklist.args.member_or_role.name'),
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.blacklist.description'),
|
description: i18n('commands.blacklist.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.blacklist.name'),
|
name: i18n('commands.blacklist.name'),
|
||||||
permissions: ['MANAGE_GUILD'],
|
options: [
|
||||||
process_args: false
|
{
|
||||||
|
description: i18n('commands.blacklist.options.add.description'),
|
||||||
|
name: i18n('commands.blacklist.options.add.name'),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.blacklist.options.add.options.member_or_role.description'),
|
||||||
|
name: i18n('commands.blacklist.options.add.options.member_or_role.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.MENTIONABLE
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: Command.option_types.SUB_COMMAND
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.blacklist.options.remove.description'),
|
||||||
|
name: i18n('commands.blacklist.options.remove.name'),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.blacklist.options.remove.options.member_or_role.description'),
|
||||||
|
name: i18n('commands.blacklist.options.remove.options.member_or_role.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.MENTIONABLE
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: Command.option_types.SUB_COMMAND
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.blacklist.options.show.description'),
|
||||||
|
name: i18n('commands.blacklist.options.show.name'),
|
||||||
|
type: Command.option_types.SUB_COMMAND
|
||||||
|
}
|
||||||
|
],
|
||||||
|
staff_only: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message, args) {
|
async execute(interaction) {
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
|
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
const blacklist = JSON.parse(JSON.stringify(settings.blacklist)); // not the same as `const blacklist = { ...settings.blacklist };` ..?
|
||||||
|
|
||||||
const member = message.mentions.members.first();
|
switch (interaction.options.getSubcommand()) {
|
||||||
|
case default_i18n('commands.blacklist.options.add.name'): {
|
||||||
|
const member_or_role = interaction.options.getMentionable(default_i18n('commands.blacklist.options.add.options.member_or_role.name'));
|
||||||
|
const type = member_or_role instanceof Role ? 'role' : 'member';
|
||||||
|
|
||||||
if (member && (await this.client.utils.isStaff(member) || member.permissions.has(this.permissions))) {
|
if (type === 'member' && await this.client.utils.isStaff(member_or_role)) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.blacklist.response.illegal_action.title'))
|
.setTitle(i18n('commands.blacklist.response.illegal_action.title'))
|
||||||
.setDescription(i18n('commands.blacklist.response.illegal_action.description', `<@${member.id}>`))
|
.setDescription(i18n('commands.blacklist.response.illegal_action.description', member_or_role.toString()))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blacklist[type + 's'].push(member_or_role.id);
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.success_colour)
|
||||||
|
.setTitle(i18n(`commands.blacklist.response.${type}_added.title`))
|
||||||
|
.setDescription(i18n(`commands.blacklist.response.${type}_added.description`, member_or_role.id))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
await settings.update({ blacklist });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case default_i18n('commands.blacklist.options.remove.name'): {
|
||||||
|
const member_or_role = interaction.options.getMentionable(default_i18n('commands.blacklist.options.remove.options.member_or_role.name'));
|
||||||
|
const type = member_or_role instanceof Role ? 'role' : 'member';
|
||||||
|
const index = blacklist[type + 's'].findIndex(element => element === member_or_role.id);
|
||||||
|
|
||||||
const role = message.mentions.roles.first();
|
if (index === -1) {
|
||||||
let id;
|
return await interaction.reply({
|
||||||
const input = args.trim().split(/\s/g)[0];
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setTitle(i18n('commands.blacklist.response.invalid.title'))
|
||||||
|
.setDescription(i18n('commands.blacklist.response.invalid.description'))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (member) {
|
blacklist[type + 's'].splice(index, 1);
|
||||||
id = member.id;
|
await interaction.reply({
|
||||||
} else if (role) {
|
embeds: [
|
||||||
id = role.id;
|
new MessageEmbed()
|
||||||
} else if (/\d{17,19}/.test(input)) {
|
.setColor(settings.success_colour)
|
||||||
id = input;
|
.setTitle(i18n(`commands.blacklist.response.${type}_removed.title`))
|
||||||
} else if (settings.blacklist.length === 0) {
|
.setDescription(i18n(`commands.blacklist.response.${type}_removed.description`, member_or_role.id))
|
||||||
return await message.channel.send({
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
await settings.update({ blacklist });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case default_i18n('commands.blacklist.options.show.name'): {
|
||||||
|
if (blacklist.members.length === 0 && blacklist.roles.length === 0) {
|
||||||
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle(i18n('commands.blacklist.response.empty_list.title'))
|
.setTitle(i18n('commands.blacklist.response.empty_list.title'))
|
||||||
.setDescription(i18n('commands.blacklist.response.empty_list.description', settings.command_prefix))
|
.setDescription(i18n('commands.blacklist.response.empty_list.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// list blacklisted members
|
const members = blacklist.members.map(id => `**·** <@${id}>`);
|
||||||
const blacklist = settings.blacklist.map(element => {
|
const roles = blacklist.roles.map(id => `**·** <@&${id}>`);
|
||||||
const is_role = message.guild.roles.cache.has(element);
|
return await interaction.reply({
|
||||||
if (is_role) return `» <@&${element}> (\`${element}\`)`;
|
|
||||||
else return `» <@${element}> (\`${element}\`)`;
|
|
||||||
});
|
|
||||||
return await message.channel.send({
|
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle(i18n('commands.blacklist.response.list.title'))
|
.setTitle(i18n('commands.blacklist.response.list.title'))
|
||||||
.setDescription(blacklist.join('\n'))
|
.addField(i18n('commands.blacklist.response.list.fields.members'), members.join('\n') || 'none')
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.addField(i18n('commands.blacklist.response.list.fields.roles'), roles.join('\n') || 'none')
|
||||||
]
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const is_role = role !== undefined || message.guild.roles.cache.has(id);
|
|
||||||
const member_or_role = is_role ? 'role' : 'member';
|
|
||||||
const index = settings.blacklist.findIndex(element => element === id);
|
|
||||||
|
|
||||||
const new_blacklist = [...settings.blacklist];
|
|
||||||
|
|
||||||
if (index === -1) {
|
|
||||||
new_blacklist.push(id);
|
|
||||||
await message.channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.colour)
|
|
||||||
.setTitle(i18n(`commands.blacklist.response.${member_or_role}_added.title`))
|
|
||||||
.setDescription(i18n(`commands.blacklist.response.${member_or_role}_added.description`, id))
|
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
|
||||||
]
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
new_blacklist.splice(index, 1);
|
|
||||||
await message.channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.colour)
|
|
||||||
.setTitle(i18n(`commands.blacklist.response.${member_or_role}_removed.title`))
|
|
||||||
.setDescription(i18n(`commands.blacklist.response.${member_or_role}_removed.description`, id))
|
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
settings.blacklist = new_blacklist;
|
|
||||||
await settings.save();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,260 +1,297 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed,
|
MessageActionRow,
|
||||||
MessageMentions
|
MessageButton,
|
||||||
|
MessageEmbed
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
const { Op } = require('sequelize');
|
const { Op } = require('sequelize');
|
||||||
const toTime = require('to-time-monthsfork');
|
const ms = require('ms');
|
||||||
|
|
||||||
module.exports = class CloseCommand extends Command {
|
module.exports = class CloseCommand extends Command {
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [
|
|
||||||
i18n('commands.close.aliases.delete'),
|
|
||||||
i18n('commands.close.aliases.lock')
|
|
||||||
],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
alias: i18n('commands.close.args.ticket.alias'),
|
|
||||||
description: i18n('commands.close.args.ticket.description'),
|
|
||||||
example: i18n('commands.close.args.ticket.example'),
|
|
||||||
name: i18n('commands.close.args.ticket.name'),
|
|
||||||
required: false,
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
{
|
|
||||||
alias: i18n('commands.close.args.reason.alias'),
|
|
||||||
description: i18n('commands.close.args.reason.description'),
|
|
||||||
example: i18n('commands.close.args.reason.example'),
|
|
||||||
name: i18n('commands.close.args.reason.name'),
|
|
||||||
required: false,
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
{
|
|
||||||
alias: i18n('commands.close.args.time.alias'),
|
|
||||||
description: i18n('commands.close.args.time.description'),
|
|
||||||
example: i18n('commands.close.args.time.example'),
|
|
||||||
name: i18n('commands.close.args.time.name'),
|
|
||||||
required: false,
|
|
||||||
type: String
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.close.description'),
|
description: i18n('commands.close.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.close.name'),
|
name: i18n('commands.close.name'),
|
||||||
process_args: true
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.close.options.reason.description'),
|
||||||
|
name: i18n('commands.close.options.reason.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.close.options.ticket.description'),
|
||||||
|
name: i18n('commands.close.options.ticket.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.INTEGER
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.close.options.time.description'),
|
||||||
|
name: i18n('commands.close.options.time.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {*} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message, args) {
|
async execute(interaction) {
|
||||||
const arg_ticket = this.args[0].name;
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
const arg_reason = this.args[1].name;
|
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
|
||||||
const arg_time = this.args[2].name;
|
|
||||||
|
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
if (args[arg_time]) {
|
const reason = interaction.options.getString(default_i18n('commands.close.options.reason.name'));
|
||||||
let period;
|
const ticket = interaction.options.getInteger(default_i18n('commands.close.options.ticket.name'));
|
||||||
|
const time = interaction.options.getString(default_i18n('commands.close.options.time.name'));
|
||||||
|
|
||||||
|
if (time) {
|
||||||
|
let period;
|
||||||
try {
|
try {
|
||||||
period = toTime(args[arg_time]).ms();
|
period = ms(time);
|
||||||
} catch {
|
} catch {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.close.response.invalid_time.title'))
|
.setTitle(i18n('commands.close.response.invalid_time.title'))
|
||||||
.setDescription(i18n('commands.close.response.invalid_time.description'))
|
.setDescription(i18n('commands.close.response.invalid_time.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
||||||
where: {
|
where: {
|
||||||
guild: message.guild.id,
|
guild: interaction.guild.id,
|
||||||
last_message: { [Op.lte]: new Date(Date.now() - period) }
|
last_message: { [Op.lte]: new Date(Date.now() - period) },
|
||||||
|
open: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (tickets.count === 0) {
|
if (tickets.count === 0) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.close.response.no_tickets.title'))
|
.setTitle(i18n('commands.close.response.no_tickets.title'))
|
||||||
.setDescription(i18n('commands.close.response.no_tickets.description'))
|
.setDescription(i18n('commands.close.response.no_tickets.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const collector_message = await message.channel.send({
|
await interaction.reply({
|
||||||
|
components: [
|
||||||
|
new MessageActionRow()
|
||||||
|
.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId(`confirm_close_multiple:${interaction.id}`)
|
||||||
|
.setLabel(i18n('commands.close.response.confirm_multiple.buttons.confirm', tickets.count, tickets.count))
|
||||||
|
.setEmoji('✅')
|
||||||
|
.setStyle('SUCCESS')
|
||||||
|
)
|
||||||
|
.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId(`cancel_close_multiple:${interaction.id}`)
|
||||||
|
.setLabel(i18n('commands.close.response.confirm_multiple.buttons.cancel'))
|
||||||
|
.setEmoji('❌')
|
||||||
|
.setStyle('SECONDARY')
|
||||||
|
)
|
||||||
|
],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle(i18n('commands.close.response.confirm_multiple.title'))
|
.setTitle(i18n('commands.close.response.confirm_multiple.title'))
|
||||||
.setDescription(i18n('commands.close.response.confirm_multiple.description', tickets.count, tickets.count))
|
.setDescription(i18n('commands.close.response.confirm_multiple.description', tickets.count, tickets.count))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 30)), interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
|
|
||||||
await collector_message.react('✅');
|
|
||||||
|
|
||||||
const filter = (reaction, user) => user.id === message.author.id && reaction.emoji.name === '✅';
|
const filter = i => i.user.id === interaction.user.id && i.customId.includes(interaction.id);
|
||||||
const collector = collector_message.createReactionCollector({
|
const collector = interaction.channel.createMessageComponentCollector({
|
||||||
filter,
|
filter,
|
||||||
time: 30000
|
time: 30000
|
||||||
});
|
});
|
||||||
|
|
||||||
collector.on('collect', async () => {
|
collector.on('collect', async i => {
|
||||||
await collector_message.reactions.removeAll();
|
await i.deferUpdate();
|
||||||
|
|
||||||
await message.channel.send({
|
if (i.customId === `confirm_close_multiple:${interaction.id}`) {
|
||||||
|
for (const ticket of tickets.rows) {
|
||||||
|
await this.client.tickets.close(ticket.id, interaction.user.id, interaction.guild.id, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
await i.editReply({
|
||||||
|
components: [],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.success_colour)
|
.setColor(settings.success_colour)
|
||||||
.setTitle(i18n('commands.close.response.closed_multiple.title', tickets.count, tickets.count))
|
.setTitle(i18n('commands.close.response.closed_multiple.title', tickets.count, tickets.count))
|
||||||
.setDescription(i18n('commands.close.response.closed_multiple.description', tickets.count, tickets.count))
|
.setDescription(i18n('commands.close.response.closed_multiple.description', tickets.count, tickets.count))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await i.editReply({
|
||||||
|
components: [],
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setTitle(i18n('commands.close.response.canceled.title'))
|
||||||
|
.setDescription(i18n('commands.close.response.canceled.description'))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const ticket of tickets.rows) {
|
|
||||||
await this.client.tickets.close(ticket.id, message.author.id, message.guild.id, args[arg_reason]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collector.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
collector.on('end', async collected => {
|
collector.on('end', async collected => {
|
||||||
if (collected.size === 0) {
|
if (collected.size === 0) {
|
||||||
await collector_message.reactions.removeAll();
|
await interaction.editReply({
|
||||||
await collector_message.edit({
|
components: [],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.close.response.confirmation_timeout.title'))
|
.setTitle(i18n('commands.close.response.confirmation_timeout.title'))
|
||||||
.setDescription(i18n('commands.close.response.confirmation_timeout.description'))
|
.setDescription(i18n('commands.close.response.confirmation_timeout.description'))
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
setTimeout(async () => {
|
|
||||||
await collector_message
|
|
||||||
.delete()
|
|
||||||
.catch(() => this.client.log.warn('Failed to delete response (collector) message'));
|
|
||||||
await message
|
|
||||||
.delete()
|
|
||||||
.catch(() => this.client.log.warn('Failed to delete original message'));
|
|
||||||
}, 15000);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let t_row;
|
|
||||||
if (args[arg_ticket]) {
|
|
||||||
args[arg_ticket] = args[arg_ticket].replace(MessageMentions.CHANNELS_PATTERN, '$1');
|
|
||||||
t_row = await this.client.tickets.resolve(args[arg_ticket], message.guild.id);
|
|
||||||
|
|
||||||
|
let t_row;
|
||||||
|
if (ticket) {
|
||||||
|
t_row = await this.client.tickets.resolve(ticket, interaction.guild.id);
|
||||||
if (!t_row) {
|
if (!t_row) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.close.response.unresolvable.title'))
|
.setTitle(i18n('commands.close.response.unresolvable.title'))
|
||||||
.setDescription(i18n('commands.close.response.unresolvable.description', args[arg_ticket]))
|
.setDescription(i18n('commands.close.response.unresolvable.description', ticket))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
t_row = await this.client.db.models.Ticket.findOne({ where: { id: message.channel.id } });
|
t_row = await this.client.db.models.Ticket.findOne({ where: { id: interaction.channel.id } });
|
||||||
|
|
||||||
if (!t_row) {
|
if (!t_row) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.close.response.not_a_ticket.title'))
|
.setTitle(i18n('commands.close.response.not_a_ticket.title'))
|
||||||
.setDescription(i18n('commands.close.response.not_a_ticket.description', settings.command_prefix))
|
.setDescription(i18n('commands.close.response.not_a_ticket.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const collector_message = await message.channel.send({
|
await interaction.reply({
|
||||||
|
components: [
|
||||||
|
new MessageActionRow()
|
||||||
|
.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId(`confirm_close:${interaction.id}`)
|
||||||
|
.setLabel(i18n('commands.close.response.confirm.buttons.confirm'))
|
||||||
|
.setEmoji('✅')
|
||||||
|
.setStyle('SUCCESS')
|
||||||
|
)
|
||||||
|
.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId(`cancel_close:${interaction.id}`)
|
||||||
|
.setLabel(i18n('commands.close.response.confirm.buttons.cancel'))
|
||||||
|
.setEmoji('❌')
|
||||||
|
.setStyle('SECONDARY')
|
||||||
|
)
|
||||||
|
],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle(i18n('commands.close.response.confirm.title'))
|
.setTitle(i18n('commands.close.response.confirm.title'))
|
||||||
.setDescription(i18n('commands.close.response.confirm.description', t_row.number))
|
.setDescription(settings.log_messages ? i18n('commands.close.response.confirm.description_with_archive') : i18n('commands.close.response.confirm.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 30)), interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
|
|
||||||
await collector_message.react('✅');
|
|
||||||
|
|
||||||
const filter = (reaction, user) => user.id === message.author.id && reaction.emoji.name === '✅';
|
const filter = i => i.user.id === interaction.user.id && i.customId.includes(interaction.id);
|
||||||
const collector = collector_message.createReactionCollector({
|
const collector = interaction.channel.createMessageComponentCollector({
|
||||||
filter,
|
filter,
|
||||||
time: 30000
|
time: 30000
|
||||||
});
|
});
|
||||||
|
|
||||||
collector.on('collect', async () => {
|
collector.on('collect', async i => {
|
||||||
collector.stop();
|
await i.deferUpdate();
|
||||||
|
|
||||||
if (message.channel.id === t_row.id) {
|
if (i.customId === `confirm_close:${interaction.id}`) {
|
||||||
await collector_message.delete();
|
await this.client.tickets.close(t_row.id, interaction.user.id, interaction.guild.id, reason);
|
||||||
} else {
|
await i.editReply({
|
||||||
await collector_message.reactions.removeAll();
|
components: [],
|
||||||
await collector_message.edit({
|
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.success_colour)
|
.setColor(settings.success_colour)
|
||||||
.setTitle(i18n('commands.close.response.closed.title'))
|
.setTitle(i18n('commands.close.response.closed.title', t_row.number))
|
||||||
.setDescription(i18n('commands.close.response.closed.description', t_row.number))
|
.setDescription(i18n('commands.close.response.closed.description', t_row.number))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await i.editReply({
|
||||||
|
components: [],
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setTitle(i18n('commands.close.response.canceled.title'))
|
||||||
|
.setDescription(i18n('commands.close.response.canceled.description'))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.client.tickets.close(t_row.id, message.author.id, message.guild.id, args[arg_reason]);
|
collector.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
collector.on('end', async collected => {
|
collector.on('end', async collected => {
|
||||||
if (collected.size === 0) {
|
if (collected.size === 0) {
|
||||||
await collector_message.reactions.removeAll();
|
await interaction.editReply({
|
||||||
await collector_message.edit({
|
components: [],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.close.response.confirmation_timeout.title'))
|
.setTitle(i18n('commands.close.response.confirmation_timeout.title'))
|
||||||
.setDescription(i18n('commands.close.response.confirmation_timeout.description'))
|
.setDescription(i18n('commands.close.response.confirmation_timeout.description'))
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
setTimeout(async () => {
|
|
||||||
await collector_message
|
|
||||||
.delete()
|
|
||||||
.catch(() => this.client.log.warn('Failed to delete response (collector) message'));
|
|
||||||
await message
|
|
||||||
.delete()
|
|
||||||
.catch(() => this.client.log.warn('Failed to delete original message'));
|
|
||||||
}, 15000);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"categories": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"claiming": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"image": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"max_per_member": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name_format": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"opening_message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"opening_questions": {
|
|
||||||
"type": [
|
|
||||||
"array",
|
|
||||||
"null"
|
|
||||||
],
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ping": {
|
|
||||||
"type": [
|
|
||||||
"array",
|
|
||||||
"null"
|
|
||||||
],
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"require_topic": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"roles": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"survey": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"roles"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"colour": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"command_prefix": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"error_colour": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"footer": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"locale": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"log_messages": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"success_colour": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"surveys": {
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"tags": {
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"categories",
|
|
||||||
"colour",
|
|
||||||
"command_prefix",
|
|
||||||
"error_colour",
|
|
||||||
"footer",
|
|
||||||
"locale",
|
|
||||||
"log_messages",
|
|
||||||
"success_colour",
|
|
||||||
"surveys",
|
|
||||||
"tags"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
MessageEmbed
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
|
|
||||||
@ -8,42 +8,23 @@ module.exports = class HelpCommand extends Command {
|
|||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [
|
|
||||||
i18n('commands.help.aliases.command'),
|
|
||||||
i18n('commands.help.aliases.commands')
|
|
||||||
],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
description: i18n('commands.help.args.command.description'),
|
|
||||||
example: i18n('commands.help.args.command.example'),
|
|
||||||
name: i18n('commands.help.args.command.name'),
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.help.description'),
|
description: i18n('commands.help.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.help.name'),
|
name: i18n('commands.help.name')
|
||||||
process_args: false
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message, args) {
|
async execute(interaction) {
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
const cmd = this.manager.commands.find(command => command.aliases.includes(args.toLowerCase()));
|
const is_staff = await this.client.utils.isStaff(interaction.member);
|
||||||
|
|
||||||
if (cmd) {
|
|
||||||
return await cmd.sendUsage(message.channel, args);
|
|
||||||
} else {
|
|
||||||
const is_staff = await this.client.utils.isStaff(message.member);
|
|
||||||
const commands = this.manager.commands.filter(command => {
|
const commands = this.manager.commands.filter(command => {
|
||||||
if (command.permissions.length >= 1) return message.member.permissions.has(command.permissions);
|
if (command.permissions.length >= 1) return interaction.member.permissions.has(command.permissions);
|
||||||
else if (command.staff_only) return is_staff;
|
else if (command.staff_only) return is_staff;
|
||||||
else return true;
|
else return true;
|
||||||
});
|
});
|
||||||
@ -51,18 +32,18 @@ module.exports = class HelpCommand extends Command {
|
|||||||
const description = command.description.length > 50
|
const description = command.description.length > 50
|
||||||
? command.description.substring(0, 50) + '...'
|
? command.description.substring(0, 50) + '...'
|
||||||
: command.description;
|
: command.description;
|
||||||
return `**\`${settings.command_prefix}${command.name}\` ·** ${description}`;
|
return `**\`/${command.name}\` ·** ${description}`;
|
||||||
});
|
});
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle(i18n('commands.help.response.list.title'))
|
.setTitle(i18n('commands.help.response.list.title'))
|
||||||
.setDescription(i18n('commands.help.response.list.description', { prefix: settings.command_prefix }))
|
.setDescription(i18n('commands.help.response.list.description'))
|
||||||
.addField(i18n('commands.help.response.list.fields.commands'), list.join('\n'))
|
.addField(i18n('commands.help.response.list.fields.commands'), list.join('\n'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -1,72 +1,64 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars,
|
||||||
MessageEmbed
|
MessageActionRow,
|
||||||
|
MessageEmbed,
|
||||||
|
MessageSelectMenu
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
const { letters } = require('../utils/emoji');
|
|
||||||
const { wait } = require('../utils');
|
|
||||||
|
|
||||||
module.exports = class NewCommand extends Command {
|
module.exports = class NewCommand extends Command {
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [
|
|
||||||
i18n('commands.new.aliases.create'),
|
|
||||||
i18n('commands.new.aliases.open'),
|
|
||||||
i18n('commands.new.aliases.ticket')
|
|
||||||
],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
description: i18n('commands.new.args.topic.description'),
|
|
||||||
example: i18n('commands.new.args.topic.example'),
|
|
||||||
name: i18n('commands.new.args.topic.name'),
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.new.description'),
|
description: i18n('commands.new.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.new.name'),
|
name: i18n('commands.new.name'),
|
||||||
process_args: false
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.new.options.topic.description'),
|
||||||
|
name: i18n('commands.new.options.topic.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message, args) {
|
async execute(interaction) {
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
|
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
const editOrSend = async (msg, content) => {
|
const topic = interaction.options.getString(default_i18n('commands.new.options.topic.name'));
|
||||||
if (msg) return await msg.edit(content);
|
|
||||||
else return await message.channel.send(content);
|
|
||||||
};
|
|
||||||
|
|
||||||
const create = async (cat_row, response) => {
|
const create = async (cat_row, i) => {
|
||||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
||||||
where: {
|
where: {
|
||||||
category: cat_row.id,
|
category: cat_row.id,
|
||||||
creator: message.author.id,
|
creator: interaction.user.id,
|
||||||
open: true
|
open: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (tickets.count >= cat_row.max_per_member) {
|
if (tickets.count >= cat_row.max_per_member) {
|
||||||
if (cat_row.max_per_member === 1) {
|
if (cat_row.max_per_member === 1) {
|
||||||
response = await editOrSend(response,
|
const response = {
|
||||||
{
|
components: [],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.new.response.has_a_ticket.title'))
|
.setTitle(i18n('commands.new.response.has_a_ticket.title'))
|
||||||
.setDescription(i18n('commands.new.response.has_a_ticket.description', tickets.rows[0].id))
|
.setDescription(i18n('commands.new.response.has_a_ticket.description', tickets.rows[0].id))
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
}
|
ephemeral: true
|
||||||
);
|
};
|
||||||
|
await i ? i.editReply(response) : interaction.reply(response);
|
||||||
} else {
|
} else {
|
||||||
const list = tickets.rows.map(row => {
|
const list = tickets.rows.map(row => {
|
||||||
if (row.topic) {
|
if (row.topic) {
|
||||||
@ -77,136 +69,120 @@ module.exports = class NewCommand extends Command {
|
|||||||
return `<#${row.id}>`;
|
return `<#${row.id}>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
response = await editOrSend(response,
|
const response = {
|
||||||
{
|
components: [],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.new.response.max_tickets.title', tickets.count))
|
.setTitle(i18n('commands.new.response.max_tickets.title', tickets.count))
|
||||||
.setDescription(i18n('commands.new.response.max_tickets.description', settings.command_prefix, list.join('\n')))
|
.setDescription(i18n('commands.new.response.max_tickets.description', list.join('\n')))
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
}
|
ephemeral: true
|
||||||
);
|
};
|
||||||
|
await i ? i.editReply(response) : interaction.reply(response);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const t_row = await this.client.tickets.create(message.guild.id, message.author.id, cat_row.id, args);
|
const t_row = await this.client.tickets.create(interaction.guild.id, interaction.user.id, cat_row.id, topic);
|
||||||
response = await editOrSend(response,
|
const response = {
|
||||||
{
|
components: [],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.success_colour)
|
.setColor(settings.success_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.new.response.created.title'))
|
.setTitle(i18n('commands.new.response.created.title'))
|
||||||
.setDescription(i18n('commands.new.response.created.description', `<#${t_row.id}>`))
|
.setDescription(i18n('commands.new.response.created.description', `<#${t_row.id}>`))
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
}
|
ephemeral: true
|
||||||
);
|
};
|
||||||
|
await i ? i.editReply(response) : interaction.reply(response);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
response = await editOrSend(response,
|
const response = {
|
||||||
{
|
components: [],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.new.response.error.title'))
|
.setTitle(i18n('commands.new.response.error.title'))
|
||||||
.setDescription(error.message)
|
.setDescription(error.message)
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
}
|
ephemeral: true
|
||||||
);
|
};
|
||||||
|
await i ? i.editReply(response) : interaction.reply(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(async () => {
|
|
||||||
await response
|
|
||||||
.delete()
|
|
||||||
.catch(() => this.client.log.warn('Failed to delete response message'));
|
|
||||||
await message
|
|
||||||
.delete()
|
|
||||||
.catch(() => this.client.log.warn('Failed to delete original message'));
|
|
||||||
}, 15000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const categories = await this.client.db.models.Category.findAndCountAll({ where: { guild: message.guild.id } });
|
const categories = await this.client.db.models.Category.findAndCountAll({ where: { guild: interaction.guild.id } });
|
||||||
|
|
||||||
if (categories.count === 0) {
|
if (categories.count === 0) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.new.response.no_categories.title'))
|
.setTitle(i18n('commands.new.response.no_categories.title'))
|
||||||
.setDescription(i18n('commands.new.response.no_categories.description'))
|
.setDescription(i18n('commands.new.response.no_categories.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
} else if (categories.count === 1) {
|
} else if (categories.count === 1) {
|
||||||
create(categories.rows[0]); // skip the category selection
|
create(categories.rows[0]); // skip the category selection
|
||||||
} else {
|
} else {
|
||||||
const letters_array = Object.values(letters); // convert the A-Z emoji object to an array
|
await interaction.reply({
|
||||||
const category_list = categories.rows.map((category, i) => `${letters_array[i]} » ${category.name}`); // list category names with an A-Z emoji
|
components: [
|
||||||
const collector_message = await message.channel.send({
|
new MessageActionRow()
|
||||||
|
.addComponents(
|
||||||
|
new MessageSelectMenu()
|
||||||
|
.setCustomId(`select_category:${interaction.id}`)
|
||||||
|
.setPlaceholder('Select a category')
|
||||||
|
.addOptions(categories.rows.map(row => ({
|
||||||
|
label: row.name,
|
||||||
|
value: row.id
|
||||||
|
})))
|
||||||
|
)
|
||||||
|
],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.new.response.select_category.title'))
|
.setTitle(i18n('commands.new.response.select_category.title'))
|
||||||
.setDescription(i18n('commands.new.response.select_category.description', category_list.join('\n')))
|
.setDescription(i18n('commands.new.response.select_category.description'))
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 30)), message.guild.iconURL())
|
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 30)), interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const i in categories.rows) {
|
const filter = i => i.user.id === interaction.user.id && i.customId.includes(interaction.id);
|
||||||
collector_message.react(letters_array[i]); // add the correct number of letter reactions
|
const collector = interaction.channel.createMessageComponentCollector({
|
||||||
await wait(1000); // 1 reaction per second rate-limit
|
|
||||||
}
|
|
||||||
|
|
||||||
const filter = (reaction, user) => {
|
|
||||||
const allowed = letters_array.slice(0, categories.count); // get the first x letters of the emoji array
|
|
||||||
return user.id === message.author.id && allowed.includes(reaction.emoji.name);
|
|
||||||
};
|
|
||||||
const collector = collector_message.createReactionCollector({
|
|
||||||
filter,
|
filter,
|
||||||
time: 30000
|
time: 30000
|
||||||
});
|
});
|
||||||
|
|
||||||
collector.on('collect', async reaction => {
|
collector.on('collect', async i => {
|
||||||
|
await i.deferUpdate();
|
||||||
|
create(categories.rows.find(row => row.id === i.values[0]), i);
|
||||||
collector.stop();
|
collector.stop();
|
||||||
const index = letters_array.findIndex(value => value === reaction.emoji.name); // find where the letter is in the alphabet
|
|
||||||
if (index === -1) {
|
|
||||||
return setTimeout(async () => {
|
|
||||||
await collector_message.delete();
|
|
||||||
}, 15000);
|
|
||||||
}
|
|
||||||
await collector_message.reactions.removeAll();
|
|
||||||
create(categories.rows[index], collector_message); // create the ticket, passing the existing response message to be edited instead of creating a new one
|
|
||||||
});
|
});
|
||||||
|
|
||||||
collector.on('end', async collected => {
|
collector.on('end', async collected => {
|
||||||
if (collected.size === 0) {
|
if (collected.size === 0) {
|
||||||
await collector_message.reactions.removeAll();
|
await interaction.editReply({
|
||||||
await collector_message.edit({
|
components: [],
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.new.response.select_category_timeout.title'))
|
.setTitle(i18n('commands.new.response.select_category_timeout.title'))
|
||||||
.setDescription(i18n('commands.new.response.select_category_timeout.description'))
|
.setDescription(i18n('commands.new.response.select_category_timeout.description'))
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
setTimeout(async () => {
|
|
||||||
await collector_message
|
|
||||||
.delete()
|
|
||||||
.catch(() => this.client.log.warn('Failed to delete response (collector) message'));
|
|
||||||
await message
|
|
||||||
.delete()
|
|
||||||
.catch(() => this.client.log.warn('Failed to delete original message'));
|
|
||||||
}, 15000);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,85 +1,98 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
MessageActionRow,
|
||||||
|
MessageButton,
|
||||||
|
MessageEmbed,
|
||||||
|
MessageSelectMenu
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
const {
|
const { some } = require('../utils');
|
||||||
some, wait
|
|
||||||
} = require('../utils');
|
|
||||||
const { emojify } = require('node-emoji');
|
|
||||||
|
|
||||||
module.exports = class PanelCommand extends Command {
|
module.exports = class PanelCommand extends Command {
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
alias: i18n('commands.panel.args.title.alias'),
|
|
||||||
description: i18n('commands.panel.args.title.description'),
|
|
||||||
example: i18n('commands.panel.args.title.example'),
|
|
||||||
name: i18n('commands.panel.args.title.name'),
|
|
||||||
required: false,
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
{
|
|
||||||
alias: i18n('commands.panel.args.description.alias'),
|
|
||||||
description: i18n('commands.panel.args.description.description'),
|
|
||||||
example: i18n('commands.panel.args.description.example'),
|
|
||||||
name: i18n('commands.panel.args.description.name'),
|
|
||||||
required: true,
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
{
|
|
||||||
alias: i18n('commands.panel.args.emoji.alias'),
|
|
||||||
description: i18n('commands.panel.args.emoji.description'),
|
|
||||||
example: i18n('commands.panel.args.emoji.example'),
|
|
||||||
multiple: true,
|
|
||||||
name: i18n('commands.panel.args.emoji.name'),
|
|
||||||
required: false,
|
|
||||||
type: String
|
|
||||||
},
|
|
||||||
{
|
|
||||||
alias: i18n('commands.panel.args.categories.alias'),
|
|
||||||
description: i18n('commands.panel.args.categories.description'),
|
|
||||||
example: i18n('commands.panel.args.categories.example'),
|
|
||||||
multiple: true,
|
|
||||||
name: i18n('commands.panel.args.categories.name'),
|
|
||||||
required: true,
|
|
||||||
type: String
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.panel.description'),
|
description: i18n('commands.panel.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.panel.name'),
|
name: i18n('commands.panel.name'),
|
||||||
permissions: ['MANAGE_GUILD'],
|
options: [
|
||||||
process_args: true
|
{
|
||||||
|
description: i18n('commands.panel.options.categories.description'),
|
||||||
|
multiple: true,
|
||||||
|
name: i18n('commands.panel.options.categories.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.panel.options.description.description'),
|
||||||
|
name: i18n('commands.panel.options.description.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.panel.options.image.description'),
|
||||||
|
name: i18n('commands.panel.options.image.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.panel.options.just_type.description') + ' (false)',
|
||||||
|
name: i18n('commands.panel.options.just_type.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.BOOLEAN
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.panel.options.title.description'),
|
||||||
|
name: i18n('commands.panel.options.title.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.panel.options.thumbnail.description'),
|
||||||
|
name: i18n('commands.panel.options.thumbnail.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
}
|
||||||
|
],
|
||||||
|
staff_only: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {*} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message, args) {
|
async execute(interaction) {
|
||||||
// localised command and arg names are a pain
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
const arg_title = this.args[0].name;
|
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
|
||||||
const arg_description = this.args[1].name;
|
|
||||||
const arg_emoji = this.args[2].name;
|
|
||||||
const arg_categories = this.args[3].name;
|
|
||||||
|
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
if (!args[arg_emoji]) args[arg_emoji] = [];
|
const categories = interaction.options.getString(default_i18n('commands.panel.options.categories.name'))
|
||||||
|
.replace(/\s/g, '')
|
||||||
|
.split(',');
|
||||||
|
const description = interaction.options.getString(default_i18n('commands.panel.options.description.name'));
|
||||||
|
const image = interaction.options.getString(default_i18n('commands.panel.options.image.name'));
|
||||||
|
const just_type = interaction.options.getBoolean(default_i18n('commands.panel.options.just_type.name'));
|
||||||
|
const title = interaction.options.getString(default_i18n('commands.panel.options.title.name'));
|
||||||
|
const thumbnail = interaction.options.getString(default_i18n('commands.panel.options.thumbnail.name'));
|
||||||
|
|
||||||
args[arg_emoji] = args[arg_emoji].map(emoji => emojify(emoji.replace(/\\/g, '')));
|
if (just_type && categories.length > 1) {
|
||||||
|
return await interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setTitle(i18n('commands.panel.response.too_many_categories.title'))
|
||||||
|
.setDescription(i18n('commands.panel.response.too_many_categories.description'))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const invalid_category = await some(args[arg_categories], async id => {
|
const invalid_category = await some(categories, async id => {
|
||||||
const cat_row = await this.client.db.models.Category.findOne({
|
const cat_row = await this.client.db.models.Category.findOne({
|
||||||
where: {
|
where: {
|
||||||
guild: message.guild.id,
|
guild: interaction.guild.id,
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -87,36 +100,36 @@ module.exports = class PanelCommand extends Command {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (invalid_category) {
|
if (invalid_category) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.panel.response.invalid_category.title'))
|
.setTitle(i18n('commands.panel.response.invalid_category.title'))
|
||||||
.setDescription(i18n('commands.panel.response.invalid_category.description'))
|
.setDescription(i18n('commands.panel.response.invalid_category.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let panel_channel,
|
let panel_channel;
|
||||||
panel_message;
|
|
||||||
|
|
||||||
let categories_map = args[arg_categories][0];
|
|
||||||
|
|
||||||
const embed = new MessageEmbed()
|
const embed = new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setFooter(settings.footer, message.guild.iconURL());
|
.setFooter(settings.footer, interaction.guild.iconURL());
|
||||||
|
|
||||||
if (args[arg_title]) embed.setTitle(args[arg_title]);
|
if (description) embed.setDescription(description);
|
||||||
|
if (image) embed.setImage(image);
|
||||||
|
if (title) embed.setTitle(title);
|
||||||
|
if (thumbnail) embed.setThumbnail(thumbnail);
|
||||||
|
|
||||||
if (args[arg_emoji].length === 0) {
|
if (just_type) {
|
||||||
// reaction-less panel
|
panel_channel = await interaction.guild.channels.create('create-a-ticket', {
|
||||||
panel_channel = await message.guild.channels.create('create-a-ticket', {
|
|
||||||
permissionOverwrites: [
|
permissionOverwrites: [
|
||||||
{
|
{
|
||||||
allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY'],
|
allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY'],
|
||||||
deny: ['ATTACH_FILES', 'EMBED_LINKS', 'ADD_REACTIONS'],
|
deny: ['ATTACH_FILES', 'EMBED_LINKS', 'ADD_REACTIONS'],
|
||||||
id: message.guild.roles.everyone
|
id: interaction.guild.roles.everyone
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
allow: ['SEND_MESSAGES', 'EMBED_LINKS', 'ADD_REACTIONS'],
|
allow: ['SEND_MESSAGES', 'EMBED_LINKS', 'ADD_REACTIONS'],
|
||||||
@ -125,33 +138,18 @@ module.exports = class PanelCommand extends Command {
|
|||||||
],
|
],
|
||||||
position: 1,
|
position: 1,
|
||||||
rateLimitPerUser: 30,
|
rateLimitPerUser: 30,
|
||||||
reason: `${message.author.tag} created a new reaction-less panel`,
|
reason: `${interaction.user.tag} created a new message panel`,
|
||||||
type: 'GUILD_TEXT'
|
type: 'GUILD_TEXT'
|
||||||
});
|
});
|
||||||
|
await panel_channel.send({ embeds: [embed] });
|
||||||
embed.setDescription(args[arg_description]);
|
this.client.log.info(`${interaction.user.tag} has created a new message panel`);
|
||||||
panel_message = await panel_channel.send({ embeds: [embed] });
|
|
||||||
|
|
||||||
this.client.log.info(`${message.author.tag} has created a new reaction-less panel`);
|
|
||||||
} else {
|
} else {
|
||||||
if (args[arg_categories].length !== args[arg_emoji].length) {
|
panel_channel = await interaction.guild.channels.create('create-a-ticket', {
|
||||||
// send error
|
|
||||||
return await message.channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setTitle(i18n('commands.panel.response.mismatch.title'))
|
|
||||||
.setDescription(i18n('commands.panel.response.mismatch.description'))
|
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
|
||||||
]
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
panel_channel = await message.guild.channels.create('create-a-ticket', {
|
|
||||||
permissionOverwrites: [
|
permissionOverwrites: [
|
||||||
{
|
{
|
||||||
allow: ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY'],
|
allow: ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY'],
|
||||||
deny: ['SEND_MESSAGES', 'ADD_REACTIONS'],
|
deny: ['SEND_MESSAGES', 'ADD_REACTIONS'],
|
||||||
id: message.guild.roles.everyone
|
id: interaction.guild.roles.everyone
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
allow: ['SEND_MESSAGES', 'EMBED_LINKS', 'ADD_REACTIONS'],
|
allow: ['SEND_MESSAGES', 'EMBED_LINKS', 'ADD_REACTIONS'],
|
||||||
@ -159,58 +157,56 @@ module.exports = class PanelCommand extends Command {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
position: 1,
|
position: 1,
|
||||||
reason: `${message.author.tag} created a new panel`,
|
reason: `${interaction.user.tag} created a new panel`,
|
||||||
type: 'GUILD_TEXT'
|
type: 'GUILD_TEXT'
|
||||||
});
|
});
|
||||||
|
|
||||||
if (args[arg_emoji].length === 1) {
|
if (categories.length === 1) {
|
||||||
// single category
|
// single category
|
||||||
categories_map = {};
|
await panel_channel.send({
|
||||||
categories_map[args[arg_emoji][0]] = args[arg_categories][0];
|
components: [
|
||||||
embed.setDescription(args[arg_description]);
|
new MessageActionRow()
|
||||||
panel_message = await panel_channel.send({ embeds: [embed] });
|
.addComponents(
|
||||||
await panel_message.react(args[arg_emoji][0]);
|
new MessageButton()
|
||||||
|
.setCustomId(`panel.single:${categories[0]}`)
|
||||||
|
.setLabel(i18n('panel.create_ticket'))
|
||||||
|
.setStyle('PRIMARY')
|
||||||
|
)
|
||||||
|
],
|
||||||
|
embeds: [embed]
|
||||||
|
});
|
||||||
|
this.client.log.info(`${interaction.user.tag} has created a new button panel`);
|
||||||
} else {
|
} else {
|
||||||
// multi category
|
// multi category
|
||||||
let description = '';
|
const rows = await this.client.db.models.Category.findAll({ where: { guild: interaction.guild.id } });
|
||||||
categories_map = {};
|
await panel_channel.send({
|
||||||
|
components: [
|
||||||
for (const i in args[arg_emoji]) {
|
new MessageActionRow()
|
||||||
categories_map[args[arg_emoji][i]] = args[arg_categories][i];
|
.addComponents(
|
||||||
const cat_row = await this.client.db.models.Category.findOne({
|
new MessageSelectMenu()
|
||||||
where: {
|
.setCustomId(`panel.multiple:${panel_channel.id}`)
|
||||||
guild: message.guild.id,
|
.setPlaceholder('Select a category')
|
||||||
id: args[arg_categories][i]
|
.addOptions(rows.map(row => ({
|
||||||
}
|
label: row.name,
|
||||||
|
value: row.id
|
||||||
|
})))
|
||||||
|
)
|
||||||
|
],
|
||||||
|
embeds: [embed]
|
||||||
});
|
});
|
||||||
description += `\n> ${args[arg_emoji][i]} | ${cat_row.name}`;
|
this.client.log.info(`${interaction.user.tag} has created a new select panel`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
embed.setDescription(args[arg_description] + '\n' + description);
|
interaction.reply({
|
||||||
panel_message = await panel_channel.send({
|
content: `✅ ${panel_channel}`,
|
||||||
embeds: [
|
ephemeral: true
|
||||||
embed
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const emoji of args[arg_emoji]) {
|
|
||||||
await panel_message.react(emoji);
|
|
||||||
await wait(1000); // 1 reaction per second rate-limit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
this.client.log.info(`${message.author.tag} has created a new panel`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message.channel.send({ content: `✅ ${panel_channel}` });
|
|
||||||
|
|
||||||
await this.client.db.models.Panel.create({
|
await this.client.db.models.Panel.create({
|
||||||
categories: categories_map,
|
category: categories.length === 1 ? categories[0] : null,
|
||||||
channel: panel_channel.id,
|
channel: panel_channel.id,
|
||||||
guild: message.guild.id,
|
guild: interaction.guild.id
|
||||||
message: panel_message.id
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
MessageEmbed
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
|
|
||||||
@ -8,106 +8,104 @@ module.exports = class RemoveCommand extends Command {
|
|||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
description: i18n('commands.remove.args.member.description'),
|
|
||||||
example: i18n('commands.remove.args.member.example'),
|
|
||||||
name: i18n('commands.remove.args.member.name'),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: i18n('commands.remove.args.ticket.description'),
|
|
||||||
example: i18n('commands.remove.args.ticket.example'),
|
|
||||||
name: i18n('commands.remove.args.ticket.name'),
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.remove.description'),
|
description: i18n('commands.remove.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.remove.name'),
|
name: i18n('commands.remove.name'),
|
||||||
process_args: false
|
options: [
|
||||||
});
|
{
|
||||||
|
description: i18n('commands.remove.options.member.description'),
|
||||||
|
name: i18n('commands.remove.options.member.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.USER
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.remove.options.ticket.description'),
|
||||||
|
name: i18n('commands.remove.options.ticket.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.CHANNEL
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Message} message
|
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
|
||||||
*/
|
|
||||||
async execute(message, args) {
|
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
|
||||||
|
|
||||||
const ticket = message.mentions.channels.first() ?? message.channel;
|
|
||||||
const t_row = await this.client.tickets.resolve(ticket.id, message.guild.id);
|
|
||||||
|
|
||||||
if (!t_row) {
|
|
||||||
return await message.channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setTitle(i18n('commands.remove.response.not_a_ticket.title'))
|
|
||||||
.setDescription(i18n('commands.remove.response.not_a_ticket.description'))
|
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const member = message.mentions.members.first() ?? message.guild.members.cache.get(args);
|
/**
|
||||||
|
* @param {Interaction} interaction
|
||||||
|
* @returns {Promise<void|any>}
|
||||||
|
*/
|
||||||
|
async execute(interaction) {
|
||||||
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
|
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
|
||||||
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
|
const channel = interaction.options.getChannel(default_i18n('commands.remove.options.channel.name')) ?? interaction.channel;
|
||||||
|
const t_row = await this.client.tickets.resolve(channel.id, interaction.guild.id);
|
||||||
|
|
||||||
|
if (!t_row) {
|
||||||
|
return await interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setTitle(i18n('commands.remove.response.not_a_channel.title'))
|
||||||
|
.setDescription(i18n('commands.remove.response.not_a_channel.description'))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = interaction.options.getMember(default_i18n('commands.remove.options.member.name'));
|
||||||
|
|
||||||
if (!member) {
|
if (!member) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.remove.response.no_member.title'))
|
.setTitle(i18n('commands.remove.response.no_member.title'))
|
||||||
.setDescription(i18n('commands.remove.response.no_member.description'))
|
.setDescription(i18n('commands.remove.response.no_member.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t_row.creator !== message.author.id && !await this.client.utils.isStaff(message.member)) {
|
if (t_row.creator !== interaction.user.id && !await this.client.utils.isStaff(interaction.member)) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.remove.response.no_permission.title'))
|
.setTitle(i18n('commands.remove.response.no_permission.title'))
|
||||||
.setDescription(i18n('commands.remove.response.no_permission.description'))
|
.setDescription(i18n('commands.remove.response.no_permission.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.channel.id !== ticket.id) {
|
await interaction.reply({
|
||||||
await message.channel.send({
|
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.success_colour)
|
.setColor(settings.success_colour)
|
||||||
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.remove.response.removed.title'))
|
.setTitle(i18n('commands.remove.response.removed.title'))
|
||||||
.setDescription(i18n('commands.remove.response.removed.description', member.toString(), ticket.toString()))
|
.setDescription(i18n('commands.remove.response.removed.description', member.toString(), channel.toString()))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
await ticket.send({
|
await channel.send({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
||||||
.setTitle(i18n('ticket.member_removed.title'))
|
.setTitle(i18n('ticket.member_removed.title'))
|
||||||
.setDescription(i18n('ticket.member_removed.description', member.toString(), message.author.toString()))
|
.setDescription(i18n('ticket.member_removed.description', member.toString(), interaction.user.toString()))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
await ticket.permissionOverwrites
|
await channel.permissionOverwrites.delete(member.user.id, `${interaction.user.tag} removed ${member.user.tag} from the ticket`);
|
||||||
.get(member.user.id)
|
|
||||||
?.delete(`${message.author.tag} removed ${member.user.tag} from the ticket`);
|
|
||||||
|
|
||||||
this.client.log.info(`${message.author.tag} removed ${member.user.tag} from ${ticket.id}`);
|
this.client.log.info(`${interaction.user.tag} removed ${member.user.tag} from ${channel.id}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,201 +1,350 @@
|
|||||||
|
/* eslint-disable max-lines */
|
||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const fetch = require('node-fetch');
|
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageAttachment
|
MessageEmbed
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
const { Validator } = require('jsonschema');
|
|
||||||
|
|
||||||
module.exports = class SettingsCommand extends Command {
|
module.exports = class SettingsCommand extends Command {
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [
|
|
||||||
i18n('commands.settings.aliases.config')
|
|
||||||
],
|
|
||||||
args: [],
|
|
||||||
description: i18n('commands.settings.description'),
|
description: i18n('commands.settings.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.settings.name'),
|
name: i18n('commands.settings.name'),
|
||||||
permissions: ['MANAGE_GUILD'],
|
options: [
|
||||||
process_args: false
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.name'),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.create.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.create.name'),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.create.options.name.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.create.options.name.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.create.options.roles.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.create.options.roles.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: Command.option_types.SUB_COMMAND
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.delete.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.delete.name'),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.delete.options.id.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.delete.options.id.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: Command.option_types.SUB_COMMAND
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.name'),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.id.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.id.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.claiming.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.claiming.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.BOOLEAN
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.image.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.image.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.max_per_member.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.max_per_member.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.INTEGER
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.name.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.name.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.name_format.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.name_format.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.opening_message.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.opening_message.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.ping.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.ping.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.require_topic.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.require_topic.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.BOOLEAN
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.roles.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.roles.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.edit.options.survey.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.edit.options.survey.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: Command.option_types.SUB_COMMAND
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.categories.options.list.description'),
|
||||||
|
name: i18n('commands.settings.options.categories.options.list.name'),
|
||||||
|
type: Command.option_types.SUB_COMMAND
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: Command.option_types.SUB_COMMAND_GROUP
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.set.description'),
|
||||||
|
name: i18n('commands.settings.options.set.name'),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.set.options.close_button.description'),
|
||||||
|
name: i18n('commands.settings.options.set.options.close_button.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.BOOLEAN
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.set.options.colour.description'),
|
||||||
|
name: i18n('commands.settings.options.set.options.colour.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.set.options.error_colour.description'),
|
||||||
|
name: i18n('commands.settings.options.set.options.error_colour.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.set.options.footer.description'),
|
||||||
|
name: i18n('commands.settings.options.set.options.footer.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.set.options.locale.description'),
|
||||||
|
name: i18n('commands.settings.options.set.options.locale.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.set.options.log_messages.description'),
|
||||||
|
name: i18n('commands.settings.options.set.options.log_messages.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.BOOLEAN
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: i18n('commands.settings.options.set.options.success_colour.description'),
|
||||||
|
name: i18n('commands.settings.options.set.options.success_colour.name'),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: Command.option_types.SUB_COMMAND
|
||||||
|
}
|
||||||
|
],
|
||||||
|
permissions: ['MANAGE_GUILD']
|
||||||
});
|
});
|
||||||
|
|
||||||
this.schema = require('./extra/settings.schema.json');
|
|
||||||
this.v = new Validator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message) {
|
async execute(interaction) {
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
|
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
const attachments = [...message.attachments.values()];
|
switch (interaction.options.getSubcommand()) {
|
||||||
|
case default_i18n('commands.settings.options.categories.options.create.name'): {
|
||||||
if (attachments.length >= 1) {
|
const name = interaction.options.getString(default_i18n('commands.settings.options.categories.options.create.options.name.name'));
|
||||||
|
const roles = interaction.options.getString(default_i18n('commands.settings.options.categories.options.create.options.roles.name'))?.replace(/\s/g, '').split(',');
|
||||||
// load settings from json
|
|
||||||
this.client.log.info(`Downloading settings for "${message.guild.name}"`);
|
|
||||||
const data = await (await fetch(attachments[0].url)).json();
|
|
||||||
|
|
||||||
const {
|
|
||||||
valid, errors
|
|
||||||
} = this.v.validate(data, this.schema);
|
|
||||||
|
|
||||||
if (!valid) {
|
|
||||||
this.client.log.warn('Settings validation error');
|
|
||||||
return await message.channel.send({ content: i18n('commands.settings.response.invalid', errors.map(error => `\`${error.stack}\``).join(',\n')) });
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.colour = data.colour;
|
|
||||||
settings.command_prefix = data.command_prefix;
|
|
||||||
settings.error_colour = data.error_colour;
|
|
||||||
settings.footer = data.footer;
|
|
||||||
settings.locale = data.locale;
|
|
||||||
settings.log_messages = data.log_messages;
|
|
||||||
settings.success_colour = data.success_colour;
|
|
||||||
settings.tags = data.tags;
|
|
||||||
await settings.save();
|
|
||||||
|
|
||||||
for (const c of data.categories) {
|
|
||||||
if (c.id) {
|
|
||||||
// existing category
|
|
||||||
const cat_row = await this.client.db.models.Category.findOne({ where: { id: c.id } });
|
|
||||||
cat_row.claiming = c.claiming;
|
|
||||||
cat_row.image = c.image;
|
|
||||||
cat_row.max_per_member = c.max_per_member;
|
|
||||||
cat_row.name = c.name;
|
|
||||||
cat_row.name_format = c.name_format;
|
|
||||||
cat_row.opening_message = c.opening_message;
|
|
||||||
cat_row.opening_questions = c.opening_questions;
|
|
||||||
cat_row.ping = c.ping;
|
|
||||||
cat_row.require_topic = c.require_topic;
|
|
||||||
cat_row.roles = c.roles;
|
|
||||||
cat_row.survey = c.survey;
|
|
||||||
cat_row.save();
|
|
||||||
|
|
||||||
const cat_channel = await this.client.channels.fetch(c.id);
|
|
||||||
|
|
||||||
if (cat_channel) {
|
|
||||||
if (cat_channel.name !== c.name) await cat_channel.setName(c.name, `Tickets category updated by ${message.author.tag}`);
|
|
||||||
|
|
||||||
for (const r of c.roles) {
|
|
||||||
await cat_channel.permissionOverwrites.edit(r, {
|
|
||||||
ATTACH_FILES: true,
|
|
||||||
READ_MESSAGE_HISTORY: true,
|
|
||||||
SEND_MESSAGES: true,
|
|
||||||
VIEW_CHANNEL: true
|
|
||||||
}, `Tickets category updated by ${message.author.tag}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// create a new category
|
|
||||||
const allowed_permissions = ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY', 'SEND_MESSAGES', 'EMBED_LINKS', 'ATTACH_FILES'];
|
const allowed_permissions = ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY', 'SEND_MESSAGES', 'EMBED_LINKS', 'ATTACH_FILES'];
|
||||||
const cat_channel = await message.guild.channels.create(c.name, {
|
const cat_channel = await interaction.guild.channels.create(name, {
|
||||||
permissionOverwrites: [
|
permissionOverwrites: [
|
||||||
...[
|
...[
|
||||||
{
|
{
|
||||||
deny: ['VIEW_CHANNEL'],
|
deny: ['VIEW_CHANNEL'],
|
||||||
id: message.guild.roles.everyone
|
id: interaction.guild.roles.everyone
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
allow: allowed_permissions,
|
allow: allowed_permissions,
|
||||||
id: this.client.user.id
|
id: this.client.user.id
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
...c.roles.map(r => ({
|
...roles.map(r => ({
|
||||||
allow: allowed_permissions,
|
allow: allowed_permissions,
|
||||||
id: r
|
id: r
|
||||||
}))
|
}))
|
||||||
],
|
],
|
||||||
position: 1,
|
position: 1,
|
||||||
reason: `Tickets category created by ${message.author.tag}`,
|
reason: `Tickets category created by ${interaction.user.tag}`,
|
||||||
type: 'GUILD_CATEGORY'
|
type: 'GUILD_CATEGORY'
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.client.db.models.Category.create({
|
await this.client.db.models.Category.create({
|
||||||
claiming: c.claiming,
|
guild: interaction.guild.id,
|
||||||
guild: message.guild.id,
|
|
||||||
id: cat_channel.id,
|
id: cat_channel.id,
|
||||||
image: c.image,
|
name,
|
||||||
max_per_member: c.max_per_member,
|
roles
|
||||||
name: c.name,
|
|
||||||
name_format: c.name_format,
|
|
||||||
opening_message: c.opening_message,
|
|
||||||
opening_questions: c.opening_questions,
|
|
||||||
ping: c.ping,
|
|
||||||
require_topic: c.require_topic,
|
|
||||||
roles: c.roles,
|
|
||||||
survey: c.survey
|
|
||||||
});
|
});
|
||||||
}
|
await this.client.commands.updatePermissions(interaction.guild);
|
||||||
}
|
interaction.reply({
|
||||||
|
embeds: [
|
||||||
for (const survey in data.surveys) {
|
new MessageEmbed()
|
||||||
const survey_data = {
|
.setColor(settings.success_colour)
|
||||||
guild: message.guild.id,
|
.setTitle(i18n('commands.settings.response.category_created', name))
|
||||||
name: survey
|
],
|
||||||
};
|
ephemeral: true
|
||||||
const [s_row] = await this.client.db.models.Survey.findOrCreate({
|
|
||||||
defaults: survey_data,
|
|
||||||
where: survey_data
|
|
||||||
});
|
});
|
||||||
s_row.questions = data.surveys[survey];
|
break;
|
||||||
await s_row.save();
|
|
||||||
}
|
}
|
||||||
|
case default_i18n('commands.settings.options.categories.options.delete.name'): {
|
||||||
this.client.log.success(`Updated guild settings for "${message.guild.name}"`);
|
const category = await this.client.db.models.Category.findOne({ where: { id: interaction.options.getString(default_i18n('commands.settings.options.categories.options.delete.options.id.name')) } });
|
||||||
return await message.channel.send({ content: i18n('commands.settings.response.updated') });
|
if (category) {
|
||||||
|
const channel = this.client.channels.cache.get(interaction.options.getString(default_i18n('commands.settings.options.categories.options.delete.options.id.name')));
|
||||||
|
if (channel) channel.delete();
|
||||||
|
await category.destroy();
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.success_colour)
|
||||||
|
.setTitle(i18n('commands.settings.response.category_deleted', category.name))
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// upload settings as json to be edited
|
interaction.reply({
|
||||||
|
embeds: [
|
||||||
const categories = await this.client.db.models.Category.findAll({ where: { guild: message.guild.id } });
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
const surveys = await this.client.db.models.Survey.findAll({ where: { guild: message.guild.id } });
|
.setTitle(i18n('commands.settings.response.category_does_not_exist'))
|
||||||
|
],
|
||||||
const data = {
|
ephemeral: true
|
||||||
categories: categories.map(c => ({
|
});
|
||||||
claiming: c.claiming,
|
}
|
||||||
id: c.id,
|
break;
|
||||||
image: c.image,
|
}
|
||||||
max_per_member: c.max_per_member,
|
case default_i18n('commands.settings.options.categories.options.edit.name'): {
|
||||||
name: c.name,
|
const category = await this.client.db.models.Category.findOne({ where: { id: interaction.options.getString(default_i18n('commands.settings.options.categories.options.delete.options.id.name')) } });
|
||||||
name_format: c.name_format,
|
if (!category) {
|
||||||
opening_message: c.opening_message,
|
return interaction.reply({
|
||||||
opening_questions: c.opening_questions,
|
embeds: [
|
||||||
ping: c.ping,
|
new MessageEmbed()
|
||||||
require_topic: c.require_topic,
|
.setColor(settings.error_colour)
|
||||||
roles: c.roles,
|
.setTitle(i18n('commands.settings.response.category_does_not_exist'))
|
||||||
survey: c.survey
|
],
|
||||||
})),
|
ephemeral: true
|
||||||
colour: settings.colour,
|
});
|
||||||
command_prefix: settings.command_prefix,
|
}
|
||||||
error_colour: settings.error_colour,
|
const claiming = interaction.options.getBoolean(default_i18n('commands.settings.options.categories.options.edit.options.claiming.name'));
|
||||||
footer: settings.footer,
|
const image = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.image.name'));
|
||||||
locale: settings.locale,
|
const max_per_member = interaction.options.getInteger(default_i18n('commands.settings.options.categories.options.edit.options.max_per_member.name'));
|
||||||
log_messages: settings.log_messages,
|
const name = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.name.name'));
|
||||||
success_colour: settings.success_colour,
|
const name_format = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.name_format.name'));
|
||||||
surveys: {},
|
const opening_message = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.opening_message.name'));
|
||||||
tags: settings.tags
|
const ping = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.ping.name'));
|
||||||
};
|
const require_topic = interaction.options.getBoolean(default_i18n('commands.settings.options.categories.options.edit.options.require_topic.name'));
|
||||||
|
const roles = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.roles.name'));
|
||||||
for (const survey in surveys) {
|
const survey = interaction.options.getString(default_i18n('commands.settings.options.categories.options.edit.options.survey.name'));
|
||||||
const {
|
if (claiming !== null) category.set('claiming', claiming);
|
||||||
name, questions
|
if (max_per_member !== null) category.set('max_per_member', max_per_member);
|
||||||
} = surveys[survey];
|
if (image !== null) category.set('image', image);
|
||||||
data.surveys[name] = questions;
|
if (name !== null) category.set('name', name);
|
||||||
|
if (name_format !== null) category.set('name_format', name_format);
|
||||||
|
if (opening_message !== null) category.set('opening_message', opening_message);
|
||||||
|
if (ping !== null) category.set('ping', ping.replace(/\s/g, '').split(','));
|
||||||
|
if (require_topic !== null) category.set('require_topic', require_topic);
|
||||||
|
if (roles !== null) category.set('roles', roles.replace(/\s/g, '').split(','));
|
||||||
|
if (survey !== null) category.set('survey', survey);
|
||||||
|
await category.save();
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.success_colour)
|
||||||
|
.setTitle(i18n('commands.settings.response.category_updated', category.name))
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case default_i18n('commands.settings.options.categories.options.list.name'): {
|
||||||
|
const categories = await this.client.db.models.Category.findAll({ where: { guild: interaction.guild.id } });
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.colour)
|
||||||
|
.setTitle(i18n('commands.settings.response.category_list'))
|
||||||
|
.setDescription(categories.map(c => `- ${c.name} (\`${c.id}\`)`).join('\n'))
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case default_i18n('commands.settings.options.set.name'): {
|
||||||
|
const close_button = interaction.options.getBoolean(default_i18n('commands.settings.options.set.options.close_button.name'));
|
||||||
|
const colour = interaction.options.getString(default_i18n('commands.settings.options.set.options.colour.name'));
|
||||||
|
const error_colour = interaction.options.getString(default_i18n('commands.settings.options.set.options.error_colour.name'));
|
||||||
|
const footer = interaction.options.getString(default_i18n('commands.settings.options.set.options.footer.name'));
|
||||||
|
const locale = interaction.options.getString(default_i18n('commands.settings.options.set.options.locale.name'));
|
||||||
|
const log_messages = interaction.options.getBoolean(default_i18n('commands.settings.options.set.options.log_messages.name'));
|
||||||
|
const success_colour = interaction.options.getString(default_i18n('commands.settings.options.set.options.success_colour.name'));
|
||||||
|
if (close_button !== null) settings.set('close_button', close_button);
|
||||||
|
if (colour !== null) settings.set('colour', colour.toUpperCase());
|
||||||
|
if (error_colour !== null) settings.set('error_colour', error_colour.toUpperCase());
|
||||||
|
if (footer !== null) settings.set('footer', footer);
|
||||||
|
if (locale !== null) settings.set('locale', locale);
|
||||||
|
if (log_messages !== null) settings.set('log_messages', log_messages);
|
||||||
|
if (success_colour !== null) settings.set('success_colour', success_colour.toUpperCase());
|
||||||
|
await settings.save();
|
||||||
|
interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.success_colour)
|
||||||
|
.setTitle(i18n('commands.settings.response.settings_updated'))
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attachment = new MessageAttachment(
|
|
||||||
Buffer.from(JSON.stringify(data, null, 2)),
|
|
||||||
`Settings for ${message.guild.name}.json`
|
|
||||||
);
|
|
||||||
|
|
||||||
return await message.channel.send({ files: [attachment] });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -1,7 +1,7 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const Keyv = require('keyv');
|
const Keyv = require('keyv');
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
MessageEmbed
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
|
|
||||||
@ -9,12 +9,9 @@ module.exports = class StatsCommand extends Command {
|
|||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [],
|
|
||||||
args: [],
|
|
||||||
description: i18n('commands.stats.description'),
|
description: i18n('commands.stats.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.stats.name'),
|
name: i18n('commands.stats.name'),
|
||||||
process_args: false,
|
|
||||||
staff_only: true
|
staff_only: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -22,25 +19,24 @@ module.exports = class StatsCommand extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message) {
|
async execute(interaction) {
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
const messages = await this.client.db.models.Message.findAndCountAll();
|
const messages = await this.client.db.models.Message.findAndCountAll();
|
||||||
|
|
||||||
let stats = await this.cache.get(message.guild.id);
|
let stats = await this.cache.get(interaction.guild.id);
|
||||||
|
|
||||||
if (!stats) {
|
if (!stats) {
|
||||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({ where: { guild: message.guild.id } });
|
const tickets = await this.client.db.models.Ticket.findAndCountAll({ where: { guild: interaction.guild.id } });
|
||||||
stats = { // maths
|
stats = { // maths
|
||||||
messages: settings.log_messages
|
messages: settings.log_messages
|
||||||
? await messages.rows
|
? await messages.rows
|
||||||
.reduce(async (acc, row) => (await this.client.db.models.Ticket.findOne({ where: { id: row.ticket } }))
|
.reduce(async (acc, row) => (await this.client.db.models.Ticket.findOne({ where: { id: row.ticket } }))
|
||||||
.guild === message.guild.id
|
.guild === interaction.guild.id
|
||||||
? await acc + 1
|
? await acc + 1
|
||||||
: await acc, 0)
|
: await acc, 0)
|
||||||
: null,
|
: null,
|
||||||
@ -49,38 +45,51 @@ module.exports = class StatsCommand extends Command {
|
|||||||
: acc, 0) / tickets.count),
|
: acc, 0) / tickets.count),
|
||||||
tickets: tickets.count
|
tickets: tickets.count
|
||||||
};
|
};
|
||||||
await this.cache.set(message.guild.id, stats, 60 * 60 * 1000); // cache for an hour
|
await this.cache.set(interaction.guild.id, stats, 60 * 60 * 1000); // cache for an hour
|
||||||
}
|
}
|
||||||
|
|
||||||
const guild_embed = new MessageEmbed()
|
const guild_embed = new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle(i18n('commands.stats.response.guild.title'))
|
.setTitle(i18n('commands.stats.response.guild.title'))
|
||||||
.setDescription(i18n('commands.stats.response.guild.description'))
|
.setDescription(i18n('commands.stats.response.guild.description'))
|
||||||
.addField(i18n('commands.stats.fields.tickets'), stats.tickets, true)
|
.addField(i18n('commands.stats.fields.tickets'), String(stats.tickets), true)
|
||||||
.addField(i18n('commands.stats.fields.response_time.title'), i18n('commands.stats.fields.response_time.minutes', stats.response_time), true)
|
.addField(i18n('commands.stats.fields.response_time.title'), i18n('commands.stats.fields.response_time.minutes', stats.response_time), true)
|
||||||
.setFooter(settings.footer, message.guild.iconURL());
|
.setFooter(settings.footer, interaction.guild.iconURL());
|
||||||
|
|
||||||
if (stats.messages) guild_embed.addField(i18n('commands.stats.fields.messages'), stats.messages, true);
|
if (stats.messages) guild_embed.addField(i18n('commands.stats.fields.messages'), String(stats.messages), true);
|
||||||
|
|
||||||
await message.channel.send({
|
const embeds = [guild_embed];
|
||||||
embeds: [
|
|
||||||
guild_embed
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.client.guilds.cache.size > 1) {
|
if (this.client.guilds.cache.size > 1) {
|
||||||
await message.channel.send({
|
let global = await this.cache.get('global');
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
if (!global) {
|
||||||
|
const tickets = await this.client.db.models.Ticket.findAndCountAll();
|
||||||
|
global = { // maths
|
||||||
|
messages: settings.log_messages
|
||||||
|
? await messages.count
|
||||||
|
: null,
|
||||||
|
response_time: Math.floor(tickets.rows.reduce((acc, row) => row.first_response
|
||||||
|
? acc + ((Math.abs(new Date(row.createdAt) - new Date(row.first_response)) / 1000) / 60)
|
||||||
|
: acc, 0) / tickets.count),
|
||||||
|
tickets: tickets.count
|
||||||
|
};
|
||||||
|
await this.cache.set('global', global, 60 * 60 * 1000); // cache for an hour
|
||||||
|
}
|
||||||
|
|
||||||
|
const global_embed = new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle(i18n('commands.stats.response.global.title'))
|
.setTitle(i18n('commands.stats.response.global.title'))
|
||||||
.setDescription(i18n('commands.stats.response.global.description'))
|
.setDescription(i18n('commands.stats.response.global.description'))
|
||||||
.addField(i18n('commands.stats.fields.tickets'), stats.tickets, true)
|
.addField(i18n('commands.stats.fields.tickets'), String(global.tickets), true)
|
||||||
.addField(i18n('commands.stats.fields.response_time.title'), i18n('commands.stats.fields.response_time.minutes', stats.response_time), true)
|
.addField(i18n('commands.stats.fields.response_time.title'), i18n('commands.stats.fields.response_time.minutes', global.response_time), true)
|
||||||
.addField(i18n('commands.stats.fields.messages'), stats.messages, true)
|
.setFooter(settings.footer, interaction.guild.iconURL());
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
|
||||||
]
|
if (stats.messages) global_embed.addField(i18n('commands.stats.fields.messages'), String(global.messages), true);
|
||||||
});
|
|
||||||
|
embeds.push(global_embed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await interaction.reply({ embeds });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -13,38 +13,44 @@ module.exports = class SurveyCommand extends Command {
|
|||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [
|
|
||||||
i18n('commands.survey.aliases.surveys')
|
|
||||||
],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
description: i18n('commands.survey.args.survey.description'),
|
|
||||||
example: i18n('commands.survey.args.survey.example'),
|
|
||||||
name: i18n('commands.survey.args.survey.name'),
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.survey.description'),
|
description: i18n('commands.survey.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.survey.name'),
|
name: i18n('commands.survey.name'),
|
||||||
process_args: false,
|
options: async guild => {
|
||||||
|
const surveys = await this.client.db.models.Survey.findAll({ where: { guild: guild.id } });
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
choices: surveys.map(survey => ({
|
||||||
|
name: survey.name,
|
||||||
|
value: survey.name
|
||||||
|
})),
|
||||||
|
description: i18n('commands.survey.options.survey.description'),
|
||||||
|
name: i18n('commands.survey.options.survey.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
}
|
||||||
|
];
|
||||||
|
},
|
||||||
staff_only: true
|
staff_only: true
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message, args) {
|
async execute(interaction) {
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
|
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
|
const name = interaction.options.getString(default_i18n('commands.survey.options.survey.name'));
|
||||||
|
|
||||||
const survey = await this.client.db.models.Survey.findOne({
|
const survey = await this.client.db.models.Survey.findOne({
|
||||||
where: {
|
where: {
|
||||||
guild: message.guild.id,
|
guild: interaction.guild.id,
|
||||||
name: args
|
name
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -55,7 +61,6 @@ module.exports = class SurveyCommand extends Command {
|
|||||||
|
|
||||||
const users = new Set();
|
const users = new Set();
|
||||||
|
|
||||||
|
|
||||||
for (const i in responses) {
|
for (const i in responses) {
|
||||||
const ticket = await this.client.db.models.Ticket.findOne({ where: { id: responses[i].ticket } });
|
const ticket = await this.client.db.models.Ticket.findOne({ where: { id: responses[i].ticket } });
|
||||||
users.add(ticket.creator);
|
users.add(ticket.creator);
|
||||||
@ -85,19 +90,23 @@ module.exports = class SurveyCommand extends Command {
|
|||||||
`${survey.name}.html`
|
`${survey.name}.html`
|
||||||
);
|
);
|
||||||
|
|
||||||
return await message.channel.send({ files: [attachment] });
|
return await interaction.reply({
|
||||||
|
ephemeral: true,
|
||||||
|
files: [attachment]
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const surveys = await this.client.db.models.Survey.findAll({ where: { guild: message.guild.id } });
|
const surveys = await this.client.db.models.Survey.findAll({ where: { guild: interaction.guild.id } });
|
||||||
|
|
||||||
const list = surveys.map(s => `❯ **\`${s.name}\`**`);
|
const list = surveys.map(s => `❯ **\`${s.name}\`**`);
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle(i18n('commands.survey.response.list.title'))
|
.setTitle(i18n('commands.survey.response.list.title'))
|
||||||
.setDescription(list.join('\n'))
|
.setDescription(list.join('\n'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,132 +1,72 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
MessageEmbed
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
const { parseArgsStringToArgv: argv } = require('string-argv');
|
|
||||||
const parseArgs = require('command-line-args');
|
|
||||||
|
|
||||||
module.exports = class TagCommand extends Command {
|
module.exports = class TagCommand extends Command {
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [
|
|
||||||
i18n('commands.tag.aliases.faq'),
|
|
||||||
i18n('commands.tag.aliases.t'),
|
|
||||||
i18n('commands.tag.aliases.tags')
|
|
||||||
],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
description: i18n('commands.tag.args.command.description'),
|
|
||||||
example: i18n('commands.tag.args.tag.example'),
|
|
||||||
name: i18n('commands.tag.args.tag.name'),
|
|
||||||
required: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.tag.description'),
|
description: i18n('commands.tag.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.tag.name'),
|
name: i18n('commands.tag.name'),
|
||||||
process_args: false,
|
options: async guild => {
|
||||||
|
const settings = await client.utils.getSettings(guild.id);
|
||||||
|
return Object.keys(settings.tags).map(tag => ({
|
||||||
|
description: settings.tags[tag].substring(0, 100),
|
||||||
|
name: tag,
|
||||||
|
options: [...settings.tags[tag].matchAll(/(?<!\\){{1,2}\s?([A-Za-z0-9._:]+)\s?(?<!\\)}{1,2}/gi)]
|
||||||
|
.map(match => ({
|
||||||
|
description: match[1],
|
||||||
|
name: match[1],
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
})),
|
||||||
|
required: false,
|
||||||
|
type: Command.option_types.SUB_COMMAND
|
||||||
|
}));
|
||||||
|
},
|
||||||
staff_only: true
|
staff_only: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message, args) {
|
async execute(interaction) {
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: message.channel.id } });
|
const tag_name = interaction.options.getSubcommand();
|
||||||
|
|
||||||
args = args.split(/\s/g); // convert to an array
|
|
||||||
const tag_name = args.shift(); // shift the first element
|
|
||||||
args = args.join(' '); // convert back to a string with the first word removed
|
|
||||||
|
|
||||||
if (tag_name && settings.tags[tag_name]) {
|
|
||||||
const tag = settings.tags[tag_name];
|
const tag = settings.tags[tag_name];
|
||||||
const placeholders = [...tag.matchAll(/(?<!\\){{1,2}\s?([A-Za-z0-9._:]+)\s?(?<!\\)}{1,2}/gi)].map(p => p[1]);
|
const args = interaction.options.data[0]?.options;
|
||||||
const requires_ticket = placeholders.some(p => p.startsWith('ticket.'));
|
|
||||||
|
|
||||||
if (requires_ticket && !t_row) {
|
if (tag) {
|
||||||
return await message.channel.send({
|
const text = tag.replace(/(?<!\\){{1,2}\s?([A-Za-z0-9._:]+)\s?(?<!\\)}{1,2}/gi, ($, $1) => {
|
||||||
embeds: [
|
const arg = args.find(arg => arg.name === $1);
|
||||||
new MessageEmbed()
|
return arg ? arg.value : $;
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setTitle(i18n('commands.tag.response.not_a_ticket.title'))
|
|
||||||
.setDescription(i18n('commands.tag.response.not_a_ticket.description'))
|
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
}
|
return await interaction.reply({
|
||||||
|
|
||||||
const expected = placeholders
|
|
||||||
.filter(p => p.startsWith(':'))
|
|
||||||
.map(p => ({
|
|
||||||
name: p.substr(1, p.length),
|
|
||||||
type: String
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (expected.length >= 1) {
|
|
||||||
try {
|
|
||||||
args = parseArgs(expected, { argv: argv(args) });
|
|
||||||
} catch (error) {
|
|
||||||
return await message.channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setTitle(i18n('commands.tag.response.error'))
|
|
||||||
.setDescription(`\`\`\`${error.message}\`\`\``)
|
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
args = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const p of expected) {
|
|
||||||
if (!args[p.name]) {
|
|
||||||
const list = expected.map(p => `\`${p.name}\``);
|
|
||||||
return await message.channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setTitle(i18n('commands.tag.response.error'))
|
|
||||||
.setDescription(i18n('commands.tag.response.missing', list.join(', ')))
|
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requires_ticket) {
|
|
||||||
args.ticket = t_row.toJSON();
|
|
||||||
args.ticket.topic = t_row.topic ? this.client.cryptr.decrypt(t_row.topic) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// note that this regex is slightly different to the other
|
|
||||||
const text = tag.replace(/(?<!\\){{1,2}\s?:?([A-Za-z0-9._]+)\s?(?<!\\)}{1,2}/gi, (_$, $1) => this.client.i18n.resolve(args, $1));
|
|
||||||
return await message.channel.send({
|
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setDescription(text)
|
.setDescription(text)
|
||||||
]
|
],
|
||||||
|
ephemeral: false
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const list = Object.keys(settings.tags).map(t => `❯ **\`${t}\`**`);
|
const list = Object.keys(settings.tags).map(t => `❯ **\`${t}\`**`);
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle(i18n('commands.tag.response.list.title'))
|
.setTitle(i18n('commands.tag.response.list.title'))
|
||||||
.setDescription(list.join('\n'))
|
.setDescription(list.join('\n'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const Command = require('../modules/commands/command');
|
const Command = require('../modules/commands/command');
|
||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
MessageEmbed
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
|
|
||||||
@ -8,55 +8,56 @@ module.exports = class TopicCommand extends Command {
|
|||||||
constructor(client) {
|
constructor(client) {
|
||||||
const i18n = client.i18n.getLocale(client.config.locale);
|
const i18n = client.i18n.getLocale(client.config.locale);
|
||||||
super(client, {
|
super(client, {
|
||||||
aliases: [],
|
|
||||||
args: [
|
|
||||||
{
|
|
||||||
description: i18n('commands.topic.args.new_topic.description'),
|
|
||||||
example: i18n('commands.topic.args.new_topic.example'),
|
|
||||||
name: i18n('commands.topic.args.new_topic.name'),
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: i18n('commands.topic.description'),
|
description: i18n('commands.topic.description'),
|
||||||
internal: true,
|
internal: true,
|
||||||
name: i18n('commands.topic.name'),
|
name: i18n('commands.topic.name'),
|
||||||
process_args: false
|
options: [
|
||||||
|
{
|
||||||
|
description: i18n('commands.topic.options.new_topic.description'),
|
||||||
|
name: i18n('commands.topic.options.new_topic.name'),
|
||||||
|
required: true,
|
||||||
|
type: Command.option_types.STRING
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Message} message
|
* @param {Interaction} interaction
|
||||||
* @param {string} args
|
|
||||||
* @returns {Promise<void|any>}
|
* @returns {Promise<void|any>}
|
||||||
*/
|
*/
|
||||||
async execute(message, args) {
|
async execute(interaction) {
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
|
const default_i18n = this.client.i18n.getLocale(this.client.config.defaults.locale); // command properties could be in a different locale
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: message.channel.id } });
|
const topic = interaction.options.getString(default_i18n('commands.topic.options.new_topic.name'));
|
||||||
|
|
||||||
|
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: interaction.channel.id } });
|
||||||
|
|
||||||
if (!t_row) {
|
if (!t_row) {
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('commands.topic.response.not_a_ticket.title'))
|
.setTitle(i18n('commands.topic.response.not_a_ticket.title'))
|
||||||
.setDescription(i18n('commands.topic.response.not_a_ticket.description'))
|
.setDescription(i18n('commands.topic.response.not_a_ticket.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await t_row.update({ topic: this.client.cryptr.encrypt(args) });
|
await t_row.update({ topic: this.client.cryptr.encrypt(topic) });
|
||||||
|
|
||||||
const member = await message.guild.members.fetch(t_row.creator);
|
const member = await interaction.guild.members.fetch(t_row.creator);
|
||||||
/* await */message.channel.setTopic(`${member} | ${args}`, { reason: 'User updated ticket topic' });
|
interaction.channel.setTopic(`${member} | ${topic}`, { reason: 'User updated ticket topic' });
|
||||||
|
|
||||||
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
|
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
|
||||||
const description = cat_row.opening_message
|
const description = cat_row.opening_message
|
||||||
.replace(/{+\s?(user)?name\s?}+/gi, member.displayName)
|
.replace(/{+\s?(user)?name\s?}+/gi, member.displayName)
|
||||||
.replace(/{+\s?(tag|ping|mention)?\s?}+/gi, member.user.toString());
|
.replace(/{+\s?(tag|ping|mention)?\s?}+/gi, member.user.toString());
|
||||||
const opening_message = await message.channel.messages.fetch(t_row.opening_message);
|
const opening_message = await interaction.channel.messages.fetch(t_row.opening_message);
|
||||||
|
|
||||||
await opening_message.edit({
|
await opening_message.edit({
|
||||||
embeds: [
|
embeds: [
|
||||||
@ -64,22 +65,23 @@ module.exports = class TopicCommand extends Command {
|
|||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
||||||
.setDescription(description)
|
.setDescription(description)
|
||||||
.addField(i18n('ticket.opening_message.fields.topic'), args)
|
.addField(i18n('ticket.opening_message.fields.topic'), topic)
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
await message.channel.send({
|
await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.success_colour)
|
.setColor(settings.success_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.topic.response.changed.title'))
|
.setTitle(i18n('commands.topic.response.changed.title'))
|
||||||
.setDescription(i18n('commands.topic.response.changed.description'))
|
.setDescription(i18n('commands.topic.response.changed.description'))
|
||||||
.setFooter(settings.footer, message.guild.iconURL())
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
]
|
],
|
||||||
|
ephemeral: false
|
||||||
});
|
});
|
||||||
|
|
||||||
this.client.log.info(`${message.author.tag} changed the topic of ${message.channel.id}`);
|
this.client.log.info(`${interaction.user.tag} changed the topic of #${interaction.channel.name}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -39,7 +39,8 @@ module.exports = async client => {
|
|||||||
logging: text => client.log.debug(text),
|
logging: text => client.log.debug(text),
|
||||||
storage: path('./user/database.sqlite')
|
storage: path('./user/database.sqlite')
|
||||||
});
|
});
|
||||||
client.log.warn('SQLite is not sufficient for a production environment if you want to use ticket archives. You should disable "log_messages" in your servers\' settings or use a different database.');
|
client.config.defaults.log_messages = false;
|
||||||
|
client.log.warn('Message logging is disabled due to insufficient database');
|
||||||
} else {
|
} else {
|
||||||
client.log.info(`Connecting to ${types[type].name} database...`);
|
client.log.info(`Connecting to ${types[type].name} database...`);
|
||||||
sequelize = new Sequelize(DB_NAME, DB_USER, DB_PASS, {
|
sequelize = new Sequelize(DB_NAME, DB_USER, DB_PASS, {
|
||||||
@ -66,7 +67,7 @@ module.exports = async client => {
|
|||||||
require(`./models/${model}`)(client, sequelize);
|
require(`./models/${model}`)(client, sequelize);
|
||||||
}
|
}
|
||||||
|
|
||||||
await sequelize.sync({ alter: { drop: false } });
|
await sequelize.sync({ alter: true });
|
||||||
|
|
||||||
return sequelize;
|
return sequelize;
|
||||||
};
|
};
|
@ -86,5 +86,8 @@ module.exports = ({ config }, sequelize) => {
|
|||||||
allowNull: true,
|
allowNull: true,
|
||||||
type: DataTypes.STRING
|
type: DataTypes.STRING
|
||||||
}
|
}
|
||||||
}, { tableName: DB_TABLE_PREFIX + 'categories' });
|
}, {
|
||||||
|
paranoid: true,
|
||||||
|
tableName: DB_TABLE_PREFIX + 'categories'
|
||||||
|
});
|
||||||
};
|
};
|
@ -3,7 +3,10 @@ module.exports = ({ config }, sequelize) => {
|
|||||||
const { DB_TABLE_PREFIX } = process.env;
|
const { DB_TABLE_PREFIX } = process.env;
|
||||||
sequelize.define('Guild', {
|
sequelize.define('Guild', {
|
||||||
blacklist: {
|
blacklist: {
|
||||||
defaultValue: [],
|
defaultValue: {
|
||||||
|
members: [],
|
||||||
|
roles: []
|
||||||
|
},
|
||||||
get() {
|
get() {
|
||||||
const raw_value = this.getDataValue('blacklist');
|
const raw_value = this.getDataValue('blacklist');
|
||||||
return raw_value
|
return raw_value
|
||||||
@ -14,14 +17,14 @@ module.exports = ({ config }, sequelize) => {
|
|||||||
},
|
},
|
||||||
type: DataTypes.JSON
|
type: DataTypes.JSON
|
||||||
},
|
},
|
||||||
|
close_button: {
|
||||||
|
defaultValue: false,
|
||||||
|
type: DataTypes.BOOLEAN
|
||||||
|
},
|
||||||
colour: {
|
colour: {
|
||||||
defaultValue: config.defaults.colour,
|
defaultValue: config.defaults.colour,
|
||||||
type: DataTypes.STRING
|
type: DataTypes.STRING
|
||||||
},
|
},
|
||||||
command_prefix: {
|
|
||||||
defaultValue: config.defaults.command_prefix,
|
|
||||||
type: DataTypes.STRING
|
|
||||||
},
|
|
||||||
error_colour: {
|
error_colour: {
|
||||||
defaultValue: 'RED',
|
defaultValue: 'RED',
|
||||||
type: DataTypes.STRING
|
type: DataTypes.STRING
|
||||||
|
@ -2,17 +2,9 @@ const { DataTypes } = require('sequelize');
|
|||||||
module.exports = (client, sequelize) => {
|
module.exports = (client, sequelize) => {
|
||||||
const { DB_TABLE_PREFIX } = process.env;
|
const { DB_TABLE_PREFIX } = process.env;
|
||||||
sequelize.define('Panel', {
|
sequelize.define('Panel', {
|
||||||
categories: {
|
category: {
|
||||||
allowNull: false,
|
allowNull: true,
|
||||||
get() {
|
type: DataTypes.CHAR(19)
|
||||||
const raw_value = this.getDataValue('categories');
|
|
||||||
return raw_value
|
|
||||||
? typeof raw_value === 'string'
|
|
||||||
? JSON.parse(raw_value)
|
|
||||||
: raw_value
|
|
||||||
: null;
|
|
||||||
},
|
|
||||||
type: DataTypes.JSON
|
|
||||||
},
|
},
|
||||||
channel: {
|
channel: {
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
@ -25,10 +17,6 @@ module.exports = (client, sequelize) => {
|
|||||||
model: DB_TABLE_PREFIX + 'guilds'
|
model: DB_TABLE_PREFIX + 'guilds'
|
||||||
},
|
},
|
||||||
type: DataTypes.CHAR(19)
|
type: DataTypes.CHAR(19)
|
||||||
},
|
|
||||||
message: {
|
|
||||||
allowNull: false,
|
|
||||||
type: DataTypes.CHAR(19)
|
|
||||||
}
|
}
|
||||||
}, { tableName: DB_TABLE_PREFIX + 'panels' });
|
}, { tableName: DB_TABLE_PREFIX + 'panels' });
|
||||||
};
|
};
|
@ -6,7 +6,7 @@ module.exports = class DebugEventListener extends EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async execute(data) {
|
async execute(data) {
|
||||||
if (this.client.config.debug) {
|
if (this.client.config.developer.debug) {
|
||||||
this.client.log.debug(data);
|
this.client.log.debug(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,6 @@ module.exports = class GuildCreateEventListener extends EventListener {
|
|||||||
|
|
||||||
async execute(guild) {
|
async execute(guild) {
|
||||||
this.client.log.info(`Added to "${guild.name}"`);
|
this.client.log.info(`Added to "${guild.name}"`);
|
||||||
|
this.client.commands.publish(guild);
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -7,6 +7,5 @@ module.exports = class GuildDeleteEventListener extends EventListener {
|
|||||||
|
|
||||||
async execute(guild) {
|
async execute(guild) {
|
||||||
this.client.log.info(`Removed from "${guild.name}"`);
|
this.client.log.info(`Removed from "${guild.name}"`);
|
||||||
await guild.deleteSettings();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
323
src/listeners/interactionCreate.js
Normal file
323
src/listeners/interactionCreate.js
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
const EventListener = require('../modules/listeners/listener');
|
||||||
|
const {
|
||||||
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
|
MessageActionRow,
|
||||||
|
MessageButton,
|
||||||
|
MessageEmbed
|
||||||
|
} = require('discord.js');
|
||||||
|
|
||||||
|
module.exports = class InteractionCreateEventListener extends EventListener {
|
||||||
|
constructor(client) {
|
||||||
|
super(client, { event: 'interactionCreate' });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Interaction} interaction
|
||||||
|
*/
|
||||||
|
async execute(interaction) {
|
||||||
|
this.client.log.debug(interaction);
|
||||||
|
|
||||||
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
|
const blacklisted = settings.blacklist.members.includes[interaction.user.id] ||
|
||||||
|
interaction.member?.roles.cache?.some(role => settings.blacklist.roles.includes(role));
|
||||||
|
if (blacklisted) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: i18n('blacklisted'),
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePanel = async id => {
|
||||||
|
const cat_row = await this.client.db.models.Category.findOne({ where: { id } });
|
||||||
|
|
||||||
|
if (!cat_row) {
|
||||||
|
this.client.log.warn('Could not find a category with the ID given by a panel interaction');
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setTitle(i18n('command_execution_error.title'))
|
||||||
|
.setDescription(i18n('command_execution_error.description'))
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
||||||
|
where: {
|
||||||
|
category: cat_row.id,
|
||||||
|
creator: interaction.user.id,
|
||||||
|
open: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tickets.count >= cat_row.max_per_member) {
|
||||||
|
if (cat_row.max_per_member === 1) {
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
|
.setTitle(i18n('commands.new.response.has_a_ticket.title'))
|
||||||
|
.setDescription(i18n('commands.new.response.has_a_ticket.description', tickets.rows[0].id))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const list = tickets.rows.map(row => {
|
||||||
|
if (row.topic) {
|
||||||
|
const description = row.topic.substring(0, 30);
|
||||||
|
const ellipses = row.topic.length > 30 ? '...' : '';
|
||||||
|
return `<#${row.id}>: \`${description}${ellipses}\``;
|
||||||
|
} else {
|
||||||
|
return `<#${row.id}>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
|
.setTitle(i18n('commands.new.response.max_tickets.title', tickets.count))
|
||||||
|
.setDescription(i18n('commands.new.response.max_tickets.description', list.join('\n')))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const t_row = await this.client.tickets.create(interaction.guild.id, interaction.user.id, id);
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.success_colour)
|
||||||
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
|
.setTitle(i18n('commands.new.response.created.title'))
|
||||||
|
.setDescription(i18n('commands.new.response.created.description', `<#${t_row.id}>`))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
this.client.log.error(error);
|
||||||
|
return interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
|
.setTitle(i18n('commands.new.response.error.title'))
|
||||||
|
.setDescription(error.message)
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (interaction.isCommand()) {
|
||||||
|
// handle slash commands
|
||||||
|
this.client.commands.handle(interaction);
|
||||||
|
} else if (interaction.isButton()) {
|
||||||
|
if (interaction.customId.startsWith('panel.single')) {
|
||||||
|
// handle single-category panels
|
||||||
|
handlePanel(interaction.customId.split(':')[1]);
|
||||||
|
} else if (interaction.customId.startsWith('ticket.claim')) {
|
||||||
|
// handle ticket claiming
|
||||||
|
if (!(await this.client.utils.isStaff(interaction.member))) return;
|
||||||
|
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: interaction.channel.id } });
|
||||||
|
await t_row.update({ claimed_by: interaction.user.id });
|
||||||
|
await interaction.channel.permissionOverwrites.edit(interaction.user.id, { VIEW_CHANNEL: true }, `Ticket claimed by ${interaction.user.tag}`);
|
||||||
|
|
||||||
|
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
|
||||||
|
|
||||||
|
for (const role of cat_row.roles) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(role, { VIEW_CHANNEL: false }, `Ticket claimed by ${interaction.user.tag}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.log.info(`${interaction.user.tag} has claimed "${interaction.channel.name}" in "${interaction.guild.name}"`);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.colour)
|
||||||
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
|
.setTitle(i18n('ticket.claimed.title'))
|
||||||
|
.setDescription(i18n('ticket.claimed.description', interaction.member.toString()))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const components = new MessageActionRow();
|
||||||
|
|
||||||
|
if (cat_row.claiming) {
|
||||||
|
components.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId('ticket.unclaim')
|
||||||
|
.setLabel(i18n('ticket.unclaim'))
|
||||||
|
.setEmoji('♻️')
|
||||||
|
.setStyle('SECONDARY')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.close_button) {
|
||||||
|
components.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId('ticket.close')
|
||||||
|
.setLabel(i18n('ticket.close'))
|
||||||
|
.setEmoji('✖️')
|
||||||
|
.setStyle('DANGER')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.message.edit({ components: [components] });
|
||||||
|
} else if (interaction.customId.startsWith('ticket.unclaim')) {
|
||||||
|
// handle ticket unclaiming
|
||||||
|
if (!(await this.client.utils.isStaff(interaction.member))) return;
|
||||||
|
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: interaction.channel.id } });
|
||||||
|
await t_row.update({ claimed_by: null });
|
||||||
|
|
||||||
|
await interaction.channel.permissionOverwrites.delete(interaction.user.id, `Ticket released by ${interaction.user.tag}`);
|
||||||
|
|
||||||
|
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
|
||||||
|
|
||||||
|
for (const role of cat_row.roles) {
|
||||||
|
await interaction.channel.permissionOverwrites.edit(role, { VIEW_CHANNEL: true }, `Ticket released by ${interaction.user.tag}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.log.info(`${interaction.user.tag} has released "${interaction.channel.name}" in "${interaction.guild.name}"`);
|
||||||
|
|
||||||
|
await interaction.reply({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.colour)
|
||||||
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
|
.setTitle(i18n('ticket.released.title'))
|
||||||
|
.setDescription(i18n('ticket.released.description', interaction.member.toString()))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const components = new MessageActionRow();
|
||||||
|
|
||||||
|
if (cat_row.claiming) {
|
||||||
|
components.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId('ticket.claim')
|
||||||
|
.setLabel(i18n('ticket.claim'))
|
||||||
|
.setEmoji('🙌')
|
||||||
|
.setStyle('SECONDARY')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.close_button) {
|
||||||
|
components.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId('ticket.close')
|
||||||
|
.setLabel(i18n('ticket.close'))
|
||||||
|
.setEmoji('✖️')
|
||||||
|
.setStyle('DANGER')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.message.edit({ components: [components] });
|
||||||
|
} else if (interaction.customId.startsWith('ticket.close')) {
|
||||||
|
// handle ticket close button
|
||||||
|
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: interaction.channel.id } });
|
||||||
|
await interaction.reply({
|
||||||
|
components: [
|
||||||
|
new MessageActionRow()
|
||||||
|
.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId(`confirm_close:${interaction.id}`)
|
||||||
|
.setLabel(i18n('commands.close.response.confirm.buttons.confirm'))
|
||||||
|
.setEmoji('✅')
|
||||||
|
.setStyle('SUCCESS')
|
||||||
|
)
|
||||||
|
.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId(`cancel_close:${interaction.id}`)
|
||||||
|
.setLabel(i18n('commands.close.response.confirm.buttons.cancel'))
|
||||||
|
.setEmoji('❌')
|
||||||
|
.setStyle('SECONDARY')
|
||||||
|
)
|
||||||
|
],
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.colour)
|
||||||
|
.setTitle(i18n('commands.close.response.confirm.title'))
|
||||||
|
.setDescription(settings.log_messages ? i18n('commands.close.response.confirm.description_with_archive') : i18n('commands.close.response.confirm.description'))
|
||||||
|
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 30)), interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const filter = i => i.user.id === interaction.user.id && i.customId.includes(interaction.id);
|
||||||
|
const collector = interaction.channel.createMessageComponentCollector({
|
||||||
|
filter,
|
||||||
|
time: 30000
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('collect', async i => {
|
||||||
|
await i.deferUpdate();
|
||||||
|
|
||||||
|
if (i.customId === `confirm_close:${interaction.id}`) {
|
||||||
|
await this.client.tickets.close(t_row.id, interaction.user.id, interaction.guild.id);
|
||||||
|
await i.editReply({
|
||||||
|
components: [],
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.success_colour)
|
||||||
|
.setTitle(i18n('commands.close.response.closed.title', t_row.number))
|
||||||
|
.setDescription(i18n('commands.close.response.closed.description', t_row.number))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await i.editReply({
|
||||||
|
components: [],
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setTitle(i18n('commands.close.response.canceled.title'))
|
||||||
|
.setDescription(i18n('commands.close.response.canceled.description'))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
collector.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.on('end', async collected => {
|
||||||
|
if (collected.size === 0) {
|
||||||
|
await interaction.editReply({
|
||||||
|
components: [],
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.error_colour)
|
||||||
|
.setAuthor(interaction.user.username, interaction.user.displayAvatarURL())
|
||||||
|
.setTitle(i18n('commands.close.response.confirmation_timeout.title'))
|
||||||
|
.setDescription(i18n('commands.close.response.confirmation_timeout.description'))
|
||||||
|
.setFooter(settings.footer, interaction.guild.iconURL())
|
||||||
|
],
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (interaction.isSelectMenu()) {
|
||||||
|
if (interaction.customId.startsWith('panel.multiple')) {
|
||||||
|
// handle multi-category panels and new command
|
||||||
|
handlePanel(interaction.values[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -1,6 +1,9 @@
|
|||||||
const EventListener = require('../modules/listeners/listener');
|
const EventListener = require('../modules/listeners/listener');
|
||||||
|
const fetch = require('node-fetch');
|
||||||
const { MessageEmbed } = require('discord.js');
|
const {
|
||||||
|
MessageAttachment,
|
||||||
|
MessageEmbed
|
||||||
|
} = require('discord.js');
|
||||||
|
|
||||||
module.exports = class MessageCreateEventListener extends EventListener {
|
module.exports = class MessageCreateEventListener extends EventListener {
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
@ -10,30 +13,107 @@ module.exports = class MessageCreateEventListener extends EventListener {
|
|||||||
async execute(message) {
|
async execute(message) {
|
||||||
if (!message.guild) return;
|
if (!message.guild) return;
|
||||||
|
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(message.guild.id);
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: message.channel.id } });
|
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: message.channel.id } });
|
||||||
|
|
||||||
if (t_row) {
|
if (t_row) {
|
||||||
if (settings.log_messages && !message.system) this.client.tickets.archives.addMessage(message); // add the message to the archives (if it is in a ticket channel)
|
const should_log_message = process.env.DB_TYPE.toLowerCase() !== 'sqlite' && settings.log_messages && !message.system;
|
||||||
|
if (should_log_message) this.client.tickets.archives.addMessage(message); // add the message to the archives (if it is in a ticket channel)
|
||||||
|
|
||||||
const ignore = [this.client.user.id, t_row.creator];
|
const ignore = [this.client.user.id, t_row.creator];
|
||||||
if (!t_row.first_response && !ignore.includes(message.author.id)) t_row.first_response = new Date();
|
if (!t_row.first_response && !ignore.includes(message.author.id)) t_row.first_response = new Date();
|
||||||
|
|
||||||
t_row.last_message = new Date();
|
t_row.last_message = new Date();
|
||||||
await t_row.save();
|
await t_row.save();
|
||||||
|
} else if (message.content.startsWith('tickets/')) {
|
||||||
|
if (!message.member.permissions.has('MANAGE_GUILD')) return;
|
||||||
|
|
||||||
|
const match = message.content.toLowerCase().match(/tickets\/(\w+)/i);
|
||||||
|
|
||||||
|
if (!match) return;
|
||||||
|
|
||||||
|
switch (match[1]) {
|
||||||
|
case 'surveys': {
|
||||||
|
const attachments = [...message.attachments.values()];
|
||||||
|
if (attachments.length >= 1) {
|
||||||
|
this.client.log.info(`Downloading surveys for "${message.guild.name}"`);
|
||||||
|
const data = await (await fetch(attachments[0].url)).json();
|
||||||
|
for (const survey in data) {
|
||||||
|
const survey_data = {
|
||||||
|
guild: message.guild.id,
|
||||||
|
name: survey
|
||||||
|
};
|
||||||
|
const [s_row] = await this.client.db.models.Survey.findOrCreate({
|
||||||
|
defaults: survey_data,
|
||||||
|
where: survey_data
|
||||||
|
});
|
||||||
|
s_row.questions = data[survey];
|
||||||
|
await s_row.save();
|
||||||
|
}
|
||||||
|
this.client.log.success(`Updated surveys for "${message.guild.name}"`);
|
||||||
|
message.channel.send({ content: i18n('commands.settings.response.settings_updated') });
|
||||||
|
} else {
|
||||||
|
const surveys = await this.client.db.models.Survey.findAll({ where: { guild: message.guild.id } });
|
||||||
|
const data = {};
|
||||||
|
|
||||||
|
for (const survey in surveys) {
|
||||||
|
const {
|
||||||
|
name, questions
|
||||||
|
} = surveys[survey];
|
||||||
|
data[name] = questions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachment = new MessageAttachment(
|
||||||
|
Buffer.from(JSON.stringify(data, null, 2)),
|
||||||
|
'surveys.json'
|
||||||
|
);
|
||||||
|
message.channel.send({ files: [attachment] });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'tags': {
|
||||||
|
const attachments = [...message.attachments.values()];
|
||||||
|
if (attachments.length >= 1) {
|
||||||
|
this.client.log.info(`Downloading tags for "${message.guild.name}"`);
|
||||||
|
const data = await (await fetch(attachments[0].url)).json();
|
||||||
|
settings.tags = data;
|
||||||
|
await settings.save();
|
||||||
|
this.client.log.success(`Updated tags for "${message.guild.name}"`);
|
||||||
|
this.client.commands.publish(message.guild);
|
||||||
|
message.channel.send({ content: i18n('commands.settings.response.settings_updated') });
|
||||||
|
} else {
|
||||||
|
const list = Object.keys(settings.tags).map(t => `❯ **\`${t}\`**`);
|
||||||
|
const attachment = new MessageAttachment(
|
||||||
|
Buffer.from(JSON.stringify(settings.tags, null, 2)),
|
||||||
|
'tags.json'
|
||||||
|
);
|
||||||
|
return await message.channel.send({
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setColor(settings.colour)
|
||||||
|
.setTitle(i18n('commands.tag.response.list.title'))
|
||||||
|
.setDescription(list.join('\n'))
|
||||||
|
.setFooter(settings.footer, message.guild.iconURL())
|
||||||
|
],
|
||||||
|
files: [attachment]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (message.author.bot) return;
|
if (message.author.bot) return;
|
||||||
|
|
||||||
const p_row = await this.client.db.models.Panel.findOne({ where: { channel: message.channel.id } });
|
const p_row = await this.client.db.models.Panel.findOne({ where: { channel: message.channel.id } });
|
||||||
|
|
||||||
if (p_row && typeof p_row.categories === 'string') {
|
if (p_row) {
|
||||||
// handle reaction-less panel
|
// handle message panels
|
||||||
|
|
||||||
await message.delete();
|
await message.delete();
|
||||||
|
|
||||||
const cat_row = await this.client.db.models.Category.findOne({ where: { id: p_row.categories } });
|
const cat_row = await this.client.db.models.Category.findOne({ where: { id: p_row.category } });
|
||||||
|
|
||||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
||||||
where: {
|
where: {
|
||||||
@ -72,7 +152,7 @@ module.exports = class MessageCreateEventListener extends EventListener {
|
|||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
.setAuthor(message.author.username, message.author.displayAvatarURL())
|
||||||
.setTitle(i18n('commands.new.response.max_tickets.title', tickets.count))
|
.setTitle(i18n('commands.new.response.max_tickets.title', tickets.count))
|
||||||
.setDescription(i18n('commands.new.response.max_tickets.description', settings.command_prefix, list.join('\n')))
|
.setDescription(i18n('commands.new.response.max_tickets.description', list.join('\n')))
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), message.author.iconURL());
|
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), message.author.iconURL());
|
||||||
try {
|
try {
|
||||||
response = await message.author.send({ embeds: [embed] });
|
response = await message.author.send({ embeds: [embed] });
|
||||||
@ -105,8 +185,6 @@ module.exports = class MessageCreateEventListener extends EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client.commands.handle(message); // pass the message to the command handler
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ module.exports = class MessageDeleteEventListener extends EventListener {
|
|||||||
async execute(message) {
|
async execute(message) {
|
||||||
if (!message.guild) return;
|
if (!message.guild) return;
|
||||||
|
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
const settings = await this.client.utils.getSettings(message.guild.id);
|
||||||
|
|
||||||
if (settings.log_messages && !message.system) this.client.tickets.archives.deleteMessage(message); // mark the message as deleted in the database (if it exists)
|
if (settings.log_messages && !message.system) this.client.tickets.archives.deleteMessage(message); // mark the message as deleted in the database (if it exists)
|
||||||
}
|
}
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
const EventListener = require('../modules/listeners/listener');
|
|
||||||
|
|
||||||
const { MessageEmbed } = require('discord.js');
|
|
||||||
|
|
||||||
module.exports = class MessageReactionAddEventListener extends EventListener {
|
|
||||||
constructor(client) {
|
|
||||||
super(client, { event: 'messageReactionAdd' });
|
|
||||||
}
|
|
||||||
|
|
||||||
async execute(reaction, user) {
|
|
||||||
|
|
||||||
if (reaction.partial) {
|
|
||||||
try {
|
|
||||||
await reaction.fetch();
|
|
||||||
} catch (error) {
|
|
||||||
return this.client.log.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.partial) {
|
|
||||||
try {
|
|
||||||
await user.fetch();
|
|
||||||
} catch (error) {
|
|
||||||
return this.client.log.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.id === this.client.user.id) return;
|
|
||||||
|
|
||||||
const guild = reaction.message.guild;
|
|
||||||
if (!guild) return;
|
|
||||||
|
|
||||||
const settings = await this.client.utils.getSettings(guild);
|
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
|
||||||
|
|
||||||
const channel = reaction.message.channel;
|
|
||||||
const member = await guild.members.fetch(user.id);
|
|
||||||
|
|
||||||
if (settings.blacklist.includes(user.id)) {
|
|
||||||
return this.client.log.info(`Ignoring blacklisted member ${user.tag}`);
|
|
||||||
} else {
|
|
||||||
settings.blacklist.forEach(element => {
|
|
||||||
if (guild.roles.cache.has(element) && member.roles.cache.has(element)) {
|
|
||||||
return this.client.log.info(`Ignoring member ${user.tag} with blacklisted role`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: channel.id } });
|
|
||||||
|
|
||||||
if (t_row && t_row.opening_message === reaction.message.id) {
|
|
||||||
if (reaction.emoji.name === '🙌' && await this.client.utils.isStaff(member)) {
|
|
||||||
// ticket claiming
|
|
||||||
|
|
||||||
await t_row.update({ claimed_by: member.user.id });
|
|
||||||
|
|
||||||
await channel.permissionOverwrites.edit(member.user.id, { VIEW_CHANNEL: true }, `Ticket claimed by ${member.user.tag}`);
|
|
||||||
|
|
||||||
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
|
|
||||||
|
|
||||||
for (const role of cat_row.roles) {
|
|
||||||
await channel.permissionOverwrites.edit(role, { VIEW_CHANNEL: false }, `Ticket claimed by ${member.user.tag}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.client.log.info(`${member.user.tag} has claimed "${channel.name}" in "${guild.name}"`);
|
|
||||||
|
|
||||||
await channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.colour)
|
|
||||||
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
|
||||||
.setTitle(i18n('ticket.claimed.title'))
|
|
||||||
.setDescription(i18n('ticket.claimed.description', member.toString()))
|
|
||||||
.setFooter(settings.footer, guild.iconURL())
|
|
||||||
]
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await reaction.users.remove(user.id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const p_row = await this.client.db.models.Panel.findOne({ where: { message: reaction.message.id } });
|
|
||||||
|
|
||||||
if (p_row && typeof p_row.categories !== 'string') {
|
|
||||||
// panels
|
|
||||||
await reaction.users.remove(user.id);
|
|
||||||
|
|
||||||
const category_id = p_row.categories[reaction.emoji.name];
|
|
||||||
if (!category_id) return;
|
|
||||||
|
|
||||||
const cat_row = await this.client.db.models.Category.findOne({ where: { id: category_id } });
|
|
||||||
|
|
||||||
const tickets = await this.client.db.models.Ticket.findAndCountAll({
|
|
||||||
where: {
|
|
||||||
category: cat_row.id,
|
|
||||||
creator: user.id,
|
|
||||||
open: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let response;
|
|
||||||
|
|
||||||
if (tickets.count >= cat_row.max_per_member) {
|
|
||||||
if (cat_row.max_per_member === 1) {
|
|
||||||
const embed = new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setAuthor(user.username, user.displayAvatarURL())
|
|
||||||
.setTitle(i18n('commands.new.response.has_a_ticket.title'))
|
|
||||||
.setDescription(i18n('commands.new.response.has_a_ticket.description', tickets.rows[0].id))
|
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), guild.iconURL());
|
|
||||||
try {
|
|
||||||
response = await user.send({ embeds: [embed] });
|
|
||||||
} catch {
|
|
||||||
response = await channel.send({ embeds: [embed] });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const list = tickets.rows.map(row => {
|
|
||||||
if (row.topic) {
|
|
||||||
const description = row.topic.substring(0, 30);
|
|
||||||
const ellipses = row.topic.length > 30 ? '...' : '';
|
|
||||||
return `<#${row.id}>: \`${description}${ellipses}\``;
|
|
||||||
} else {
|
|
||||||
return `<#${row.id}>`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const embed = new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setAuthor(user.username, user.displayAvatarURL())
|
|
||||||
.setTitle(i18n('commands.new.response.max_tickets.title', tickets.count))
|
|
||||||
.setDescription(i18n('commands.new.response.max_tickets.description', settings.command_prefix, list.join('\n')))
|
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), user.iconURL());
|
|
||||||
try {
|
|
||||||
response = await user.send({ embeds: [embed] });
|
|
||||||
} catch {
|
|
||||||
response = await channel.send({ embeds: [embed] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
await this.client.tickets.create(guild.id, user.id, cat_row.id);
|
|
||||||
} catch (error) {
|
|
||||||
const embed = new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setAuthor(user.username, user.displayAvatarURL())
|
|
||||||
.setTitle(i18n('commands.new.response.error.title'))
|
|
||||||
.setDescription(error.message)
|
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('message_will_be_deleted_in', 15)), guild.iconURL());
|
|
||||||
try {
|
|
||||||
response = await user.send({ embeds: [embed] });
|
|
||||||
} catch {
|
|
||||||
response = await channel.send({ embeds: [embed] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response) {
|
|
||||||
setTimeout(async () => {
|
|
||||||
await response.delete();
|
|
||||||
}, 15000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,72 +0,0 @@
|
|||||||
const EventListener = require('../modules/listeners/listener');
|
|
||||||
|
|
||||||
const { MessageEmbed } = require('discord.js');
|
|
||||||
|
|
||||||
module.exports = class MessageReactionRemoveEventListener extends EventListener {
|
|
||||||
constructor(client) {
|
|
||||||
super(client, { event: 'messageReactionRemove' });
|
|
||||||
}
|
|
||||||
|
|
||||||
async execute(reaction, user) {
|
|
||||||
// release (unclaim) ticket
|
|
||||||
if (reaction.partial) {
|
|
||||||
try {
|
|
||||||
await reaction.fetch();
|
|
||||||
} catch (error) {
|
|
||||||
return this.client.log.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.partial) {
|
|
||||||
try {
|
|
||||||
await user.fetch();
|
|
||||||
} catch (error) {
|
|
||||||
return this.client.log.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.id === this.client.user.id) return;
|
|
||||||
|
|
||||||
const guild = reaction.message.guild;
|
|
||||||
if (!guild) return;
|
|
||||||
|
|
||||||
const settings = await this.client.utils.getSettings(guild);
|
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
|
||||||
|
|
||||||
const channel = reaction.message.channel;
|
|
||||||
const member = await guild.members.fetch(user.id);
|
|
||||||
|
|
||||||
const t_row = await this.client.db.models.Ticket.findOne({ where: { id: channel.id } });
|
|
||||||
|
|
||||||
if (t_row && t_row.opening_message === reaction.message.id) {
|
|
||||||
if (reaction.emoji.name === '🙌' && await this.client.utils.isStaff(member)) {
|
|
||||||
// ticket claiming
|
|
||||||
|
|
||||||
await t_row.update({ claimed_by: null });
|
|
||||||
|
|
||||||
await channel.permissionOverwrites
|
|
||||||
.get(member.user.id)
|
|
||||||
?.delete(`Ticket released by ${member.user.tag}`);
|
|
||||||
|
|
||||||
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
|
|
||||||
|
|
||||||
for (const role of cat_row.roles) {
|
|
||||||
await channel.permissionOverwrites.edit(role, { VIEW_CHANNEL: true }, `Ticket released by ${member.user.tag}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.client.log.info(`${member.user.tag} has released "${channel.name}" in "${guild.name}"`);
|
|
||||||
|
|
||||||
await channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.colour)
|
|
||||||
.setAuthor(member.user.username, member.user.displayAvatarURL())
|
|
||||||
.setTitle(i18n('ticket.released.title'))
|
|
||||||
.setDescription(i18n('ticket.released.description', member.toString()))
|
|
||||||
.setFooter(settings.footer, guild.iconURL())
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
@ -16,7 +16,7 @@ module.exports = class MessageUpdateEventListener extends EventListener {
|
|||||||
|
|
||||||
if (!newm.guild) return;
|
if (!newm.guild) return;
|
||||||
|
|
||||||
const settings = await this.client.utils.getSettings(newm.guild);
|
const settings = await this.client.utils.getSettings(newm.guild.id);
|
||||||
|
|
||||||
if (settings.log_messages && !newm.system) this.client.tickets.archives.updateMessage(newm); // update the message in the database
|
if (settings.log_messages && !newm.system) this.client.tickets.archives.updateMessage(newm); // update the message in the database
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,10 @@ module.exports = class ReadyEventListener extends EventListener {
|
|||||||
async execute() {
|
async execute() {
|
||||||
this.client.log.success(`Connected to Discord as "${this.client.user.tag}"`);
|
this.client.log.success(`Connected to Discord as "${this.client.user.tag}"`);
|
||||||
|
|
||||||
|
this.client.log.info('Loading commands');
|
||||||
this.client.commands.load(); // load internal commands
|
this.client.commands.load(); // load internal commands
|
||||||
|
|
||||||
this.client.plugins.plugins.forEach(p => p.load()); // call load function for each plugin
|
this.client.plugins.plugins.forEach(p => p.load()); // call load function for each plugin
|
||||||
|
this.client.commands.publish(); // send commands to discord
|
||||||
|
|
||||||
if (this.client.config.presence.presences.length > 1) {
|
if (this.client.config.presence.presences.length > 1) {
|
||||||
const { selectPresence } = require('../utils/discord');
|
const { selectPresence } = require('../utils/discord');
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"blacklisted": "❌ You are blacklisted",
|
||||||
"bot": {
|
"bot": {
|
||||||
"missing_permissions": {
|
"missing_permissions": {
|
||||||
"description": "Discord Tickets requires the following permissions:\n%s",
|
"description": "Discord Tickets requires the following permissions:\n%s",
|
||||||
@ -6,36 +7,25 @@
|
|||||||
},
|
},
|
||||||
"version": "[Discord Tickets](%s) v%s by [eartharoid](%s)"
|
"version": "[Discord Tickets](%s) v%s by [eartharoid](%s)"
|
||||||
},
|
},
|
||||||
"cmd_usage": {
|
|
||||||
"args": {
|
|
||||||
"description": "**Description:** %s",
|
|
||||||
"example": "**Example:** `%s`"
|
|
||||||
},
|
|
||||||
"description": "**Usage:**\n`%s`\n\n**Example:**\n`%s`\n\nRequired arguments are prefixed with `❗`.",
|
|
||||||
"invalid_named_args": {
|
|
||||||
"description": "There is an error in your command syntax: `%s`.\nType `%s` for an example.\nPlease ask a member of staff if you are unsure.",
|
|
||||||
"title": "❌ Invalid syntax"
|
|
||||||
},
|
|
||||||
"named_args": "This command uses named arguments.\n\n",
|
|
||||||
"title": "`%s` command usage"
|
|
||||||
},
|
|
||||||
"collector_expires_in": "Expires in %d seconds",
|
"collector_expires_in": "Expires in %d seconds",
|
||||||
|
"command_execution_error": {
|
||||||
|
"description": "An unexpected error occurred during command execution.\nPlease ask an administrator to check the console output / logs for details.",
|
||||||
|
"title": "⚠️"
|
||||||
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"add": {
|
"add": {
|
||||||
"args": {
|
"description": "Add a member to a ticket",
|
||||||
|
"name": "add",
|
||||||
|
"options": {
|
||||||
"member": {
|
"member": {
|
||||||
"description": "The member to add to the ticket",
|
"description": "The member to add to the ticket",
|
||||||
"example": "@someone",
|
|
||||||
"name": "member"
|
"name": "member"
|
||||||
},
|
},
|
||||||
"ticket": {
|
"ticket": {
|
||||||
"description": "The ticket to add the member to",
|
"description": "The ticket to add the member to",
|
||||||
"example": "217",
|
|
||||||
"name": "ticket"
|
"name": "ticket"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Add a member to a ticket",
|
|
||||||
"name": "add",
|
|
||||||
"response": {
|
"response": {
|
||||||
"added": {
|
"added": {
|
||||||
"description": "%s has been added to %s.",
|
"description": "%s has been added to %s.",
|
||||||
@ -56,28 +46,52 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"blacklist": {
|
"blacklist": {
|
||||||
"aliases": {
|
"description": "View or modify the blacklist",
|
||||||
"unblacklist": "unblacklist"
|
"name": "blacklist",
|
||||||
},
|
"options": {
|
||||||
"args": {
|
"add": {
|
||||||
|
"description": "Add a member or role to the blacklist",
|
||||||
|
"name": "add",
|
||||||
|
"options": {
|
||||||
"member_or_role": {
|
"member_or_role": {
|
||||||
"description": "The member or role to add/remove",
|
"description": "The member or role to add to the blacklist",
|
||||||
"example": "@NaughtyMember",
|
"name": "member_or_role"
|
||||||
"name": "memberOrRole"
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"remove": {
|
||||||
|
"description": "Remove a member or role from the blacklist",
|
||||||
|
"name": "remove",
|
||||||
|
"options": {
|
||||||
|
"member_or_role": {
|
||||||
|
"description": "The member or role to remove from the blacklist",
|
||||||
|
"name": "member_or_role"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"show": {
|
||||||
|
"description": "Show the members and roles in the blacklist",
|
||||||
|
"name": "show"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Blacklist/unblacklist a member from interacting with the bot",
|
|
||||||
"name": "blacklist",
|
|
||||||
"response": {
|
"response": {
|
||||||
"empty_list": {
|
"empty_list": {
|
||||||
"description": "There are no members or roles blacklisted. Type `%sblacklist <memberOrRole>` to add a member or role to the blacklist.",
|
"description": "There are no members or roles blacklisted. Type `/blacklist add` to add a member or role to the blacklist.",
|
||||||
"title": "📃 Blacklisted members and roles"
|
"title": "📃 Blacklisted members and roles"
|
||||||
},
|
},
|
||||||
"illegal_action": {
|
"illegal_action": {
|
||||||
"description": "%s is a staff member and cannot be blacklisted.",
|
"description": "%s is a staff member and cannot be blacklisted.",
|
||||||
"title": "❌ You can't blacklist this member"
|
"title": "❌ You can't blacklist this member"
|
||||||
},
|
},
|
||||||
|
"invalid": {
|
||||||
|
"description": "This member or role can not be removed from the blacklist as they are not blacklisted.",
|
||||||
|
"title": "❌ Error"
|
||||||
|
},
|
||||||
"list": {
|
"list": {
|
||||||
|
"fields": {
|
||||||
|
"members": "Members",
|
||||||
|
"roles": "Roles"
|
||||||
|
},
|
||||||
"title": "📃 Blacklisted members and roles"
|
"title": "📃 Blacklisted members and roles"
|
||||||
},
|
},
|
||||||
"member_added": {
|
"member_added": {
|
||||||
@ -99,33 +113,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"close": {
|
"close": {
|
||||||
"aliases": {
|
"description": "Close a ticket channel",
|
||||||
"delete": "delete",
|
"name": "close",
|
||||||
"lock": "lock"
|
"options": {
|
||||||
},
|
|
||||||
"args": {
|
|
||||||
"reason": {
|
"reason": {
|
||||||
"alias": "r",
|
|
||||||
"description": "The reason for closing the ticket(s)",
|
"description": "The reason for closing the ticket(s)",
|
||||||
"example": "Resolved",
|
|
||||||
"name": "reason"
|
"name": "reason"
|
||||||
},
|
},
|
||||||
"ticket": {
|
"ticket": {
|
||||||
"alias": "t",
|
"description": "The ticket to close, either the number or the channel ID",
|
||||||
"description": "The ticket to close, either the number or the channel mention/ID",
|
|
||||||
"example": "217",
|
|
||||||
"name": "ticket"
|
"name": "ticket"
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"alias": "T",
|
|
||||||
"description": "Close all tickets that have been inactive for the specified time",
|
"description": "Close all tickets that have been inactive for the specified time",
|
||||||
"example": "1w",
|
|
||||||
"name": "time"
|
"name": "time"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Close a ticket channel",
|
|
||||||
"name": "close",
|
|
||||||
"response": {
|
"response": {
|
||||||
|
"canceled": {
|
||||||
|
"description": "You canceled the operation.",
|
||||||
|
"title": "🚫 Canceled"
|
||||||
|
},
|
||||||
"closed": {
|
"closed": {
|
||||||
"description": "Ticket #%s has been closed.",
|
"description": "Ticket #%s has been closed.",
|
||||||
"title": "✅ Ticket closed"
|
"title": "✅ Ticket closed"
|
||||||
@ -141,33 +149,44 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"description": "React with ✅ to close this ticket.",
|
"buttons": {
|
||||||
"description_with_archive": "You will be able to view an archived version of it after.\nReact with ✅ to close this ticket.",
|
"cancel": "Cancel",
|
||||||
|
"confirm": "Close"
|
||||||
|
},
|
||||||
|
"description": "Please confirm your decision.",
|
||||||
|
"description_with_archive": "The ticket will be archived for future reference.",
|
||||||
|
"title": "❔ Are you sure?"
|
||||||
|
},
|
||||||
|
"confirm_multiple": {
|
||||||
|
"buttons": {
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"confirm": [
|
||||||
|
"Close %d ticket",
|
||||||
|
"Close %d tickets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": [
|
||||||
|
"You are about to close %d ticket.",
|
||||||
|
"You are about to close %d tickets."
|
||||||
|
],
|
||||||
"title": "❔ Are you sure?"
|
"title": "❔ Are you sure?"
|
||||||
},
|
},
|
||||||
"confirmation_timeout": {
|
"confirmation_timeout": {
|
||||||
"description": "You took too long to confirm.",
|
"description": "You took too long to confirm.",
|
||||||
"title": "❌ Reaction time expired"
|
"title": "❌ Interaction time expired"
|
||||||
},
|
|
||||||
"confirm_multiple": {
|
|
||||||
"description": [
|
|
||||||
"React with ✅ to close %d ticket.",
|
|
||||||
"React with ✅ to close %d tickets."
|
|
||||||
],
|
|
||||||
"title": "❔ Are you sure?"
|
|
||||||
},
|
},
|
||||||
"invalid_time": {
|
"invalid_time": {
|
||||||
"description": "The time period provided could not be parsed.",
|
"description": "The time period provided could not be parsed.",
|
||||||
"title": "❌ Invalid input"
|
"title": "❌ Invalid input"
|
||||||
},
|
},
|
||||||
"not_a_ticket": {
|
|
||||||
"description": "Please use this command in a ticket channel or use the ticket flag.\nType `%shelp close` for more information.",
|
|
||||||
"title": "❌ This isn't a ticket channel"
|
|
||||||
},
|
|
||||||
"no_tickets": {
|
"no_tickets": {
|
||||||
"description": "There are no tickets which have been inactive for this time period.",
|
"description": "There are no tickets which have been inactive for this time period.",
|
||||||
"title": "❌ No tickets to close"
|
"title": "❌ No tickets to close"
|
||||||
},
|
},
|
||||||
|
"not_a_ticket": {
|
||||||
|
"description": "Please use this command in a ticket channel or use the ticket flag.\nType `/help close` for more information.",
|
||||||
|
"title": "❌ This isn't a ticket channel"
|
||||||
|
},
|
||||||
"unresolvable": {
|
"unresolvable": {
|
||||||
"description": "`%s` could not be resolved to a ticket. Please provide the ticket ID/mention or number.",
|
"description": "`%s` could not be resolved to a ticket. Please provide the ticket ID/mention or number.",
|
||||||
"title": "❌ Error"
|
"title": "❌ Error"
|
||||||
@ -175,22 +194,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"aliases": {
|
"description": "List the commands you have access to",
|
||||||
"command": "command",
|
|
||||||
"commands": "commands"
|
|
||||||
},
|
|
||||||
"args": {
|
|
||||||
"command": {
|
|
||||||
"description": "The command to display information about",
|
|
||||||
"example": "new",
|
|
||||||
"name": "command"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "List commands you have access to, or find out more about a command",
|
|
||||||
"name": "help",
|
"name": "help",
|
||||||
|
"options": {},
|
||||||
"response": {
|
"response": {
|
||||||
"list": {
|
"list": {
|
||||||
"description": "The commands you have access to are listed below. For more information about a command, type `{prefix}help [command]`. To create a ticket, type `{prefix}new [topic]`.",
|
"description": "The commands you have access to are listed below. To create a ticket, type **`/new`**.",
|
||||||
"fields": {
|
"fields": {
|
||||||
"commands": "Commands"
|
"commands": "Commands"
|
||||||
},
|
},
|
||||||
@ -199,20 +208,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"new": {
|
"new": {
|
||||||
"aliases": {
|
"description": "Create a new ticket",
|
||||||
"create": "create",
|
"name": "new",
|
||||||
"open": "open",
|
"options": {
|
||||||
"ticket": "ticket"
|
|
||||||
},
|
|
||||||
"args": {
|
|
||||||
"topic": {
|
"topic": {
|
||||||
"description": "The topic of the ticket",
|
"description": "The topic of the ticket",
|
||||||
"example": "Problem with billing",
|
|
||||||
"name": "topic"
|
"name": "topic"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Create a new ticket",
|
"request_topic": {
|
||||||
"name": "new",
|
"description": "Please briefly state what this ticket is about in a a few words.",
|
||||||
|
"title": "⚠️ Ticket topic"
|
||||||
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"created": {
|
"created": {
|
||||||
"description": "Your ticket has been created: %s.",
|
"description": "Your ticket has been created: %s.",
|
||||||
@ -226,7 +233,7 @@
|
|||||||
"title": "❌ You already have an open ticket"
|
"title": "❌ You already have an open ticket"
|
||||||
},
|
},
|
||||||
"max_tickets": {
|
"max_tickets": {
|
||||||
"description": "Please use `%sclose` to close any unneeded tickets.\n\n%s",
|
"description": "Please use `/close` to close any unneeded tickets.\n\n%s",
|
||||||
"title": "❌ You already have %d open tickets"
|
"title": "❌ You already have %d open tickets"
|
||||||
},
|
},
|
||||||
"no_categories": {
|
"no_categories": {
|
||||||
@ -234,79 +241,69 @@
|
|||||||
"title": "❌ Can't create ticket"
|
"title": "❌ Can't create ticket"
|
||||||
},
|
},
|
||||||
"select_category": {
|
"select_category": {
|
||||||
"description": "Select the category most relevant to your ticket's topic:\n\n%s",
|
"description": "Select the category most relevant to your ticket's topic.",
|
||||||
"title": "🔤 Please select the ticket category"
|
"title": "🔤 Please select the ticket category"
|
||||||
},
|
},
|
||||||
"select_category_timeout": {
|
"select_category_timeout": {
|
||||||
"description": "You took too long to select the ticket category.",
|
"description": "You took too long to select the ticket category.",
|
||||||
"title": "❌ Reaction time expired"
|
"title": "❌ Interaction time expired"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"request_topic": {
|
|
||||||
"description": "Please briefly state what this ticket is about in a a few words.",
|
|
||||||
"title": "Ticket topic"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"panel": {
|
"panel": {
|
||||||
"args": {
|
"description": "Create a new ticket panel",
|
||||||
|
"name": "panel",
|
||||||
|
"options": {
|
||||||
"categories": {
|
"categories": {
|
||||||
"alias": "c",
|
"description": "A comma-separated list of category IDs",
|
||||||
"description": "A category ID",
|
|
||||||
"example": "451745464954650634",
|
|
||||||
"name": "categories"
|
"name": "categories"
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"alias": "d",
|
|
||||||
"description": "The description for the panel message",
|
"description": "The description for the panel message",
|
||||||
"example": "\"React to this message to open a ticket.\"",
|
|
||||||
"name": "description"
|
"name": "description"
|
||||||
},
|
},
|
||||||
"emoji": {
|
"image": {
|
||||||
"alias": "e",
|
"description": "An image URL for the panel message",
|
||||||
"description": "An emoji",
|
"name": "image"
|
||||||
"example": "🎫",
|
},
|
||||||
"name": "emoji"
|
"just_type": {
|
||||||
|
"description": "Create a \"just type\" panel?",
|
||||||
|
"name": "just_type"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"alias": "t",
|
|
||||||
"description": "The title for the panel message",
|
"description": "The title for the panel message",
|
||||||
"example": "\"Support tickets\"",
|
|
||||||
"name": "title"
|
"name": "title"
|
||||||
|
},
|
||||||
|
"thumbnail": {
|
||||||
|
"description": "A thumbnail image URL for the panel message",
|
||||||
|
"name": "thumbnail"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Create a new ticket panel",
|
|
||||||
"name": "panel",
|
|
||||||
"response": {
|
"response": {
|
||||||
"invalid_category": {
|
"invalid_category": {
|
||||||
"description": "One or more of the specified category IDs is invalid.",
|
"description": "One or more of the specified category IDs is invalid.",
|
||||||
"title": "❌ Invalid category"
|
"title": "❌ Invalid category"
|
||||||
},
|
},
|
||||||
"mismatch": {
|
"too_many_categories": {
|
||||||
"description": "Please provide the name number of emojis and category IDs.",
|
"description": "The \"just type\" panel can only be used with a single category.",
|
||||||
"title": "❌ Invalid input"
|
"title": "❌ Too many categories"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"args": {
|
"description": "Remove a member from a ticket",
|
||||||
|
"name": "remove",
|
||||||
|
"options": {
|
||||||
"member": {
|
"member": {
|
||||||
"description": "The member to remove from the ticket",
|
"description": "The member to remove from the ticket",
|
||||||
"example": "@someone",
|
|
||||||
"name": "member"
|
"name": "member"
|
||||||
},
|
},
|
||||||
"ticket": {
|
"ticket": {
|
||||||
"description": "The ticket to remove the member from",
|
"description": "The ticket to remove the member from",
|
||||||
"example": "217",
|
|
||||||
"name": "ticket"
|
"name": "ticket"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Remove a member from a ticket",
|
|
||||||
"name": "remove",
|
|
||||||
"response": {
|
"response": {
|
||||||
"removed": {
|
|
||||||
"description": "%s has been removed from %s.",
|
|
||||||
"title": "✅ Member removed"
|
|
||||||
},
|
|
||||||
"no_member": {
|
"no_member": {
|
||||||
"description": "Please mention the member you want to remove.",
|
"description": "Please mention the member you want to remove.",
|
||||||
"title": "❌ Unknown member"
|
"title": "❌ Unknown member"
|
||||||
@ -318,18 +315,143 @@
|
|||||||
"not_a_ticket": {
|
"not_a_ticket": {
|
||||||
"description": "Please use this command in the ticket channel, or mention the channel.",
|
"description": "Please use this command in the ticket channel, or mention the channel.",
|
||||||
"title": "❌ This isn't a ticket channel"
|
"title": "❌ This isn't a ticket channel"
|
||||||
|
},
|
||||||
|
"removed": {
|
||||||
|
"description": "%s has been removed from %s.",
|
||||||
|
"title": "✅ Member removed"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"aliases": {
|
|
||||||
"config": "config"
|
|
||||||
},
|
|
||||||
"description": "Configure Discord Tickets",
|
"description": "Configure Discord Tickets",
|
||||||
"name": "settings",
|
"name": "settings",
|
||||||
|
"options": {
|
||||||
|
"categories": {
|
||||||
|
"description": "Manage your ticket categories",
|
||||||
|
"name": "categories",
|
||||||
|
"options": {
|
||||||
|
"create": {
|
||||||
|
"description": "Create a new category",
|
||||||
|
"name": "create",
|
||||||
|
"options": {
|
||||||
|
"name": {
|
||||||
|
"description": "The name of the category",
|
||||||
|
"name": "name"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"description": "A comma-separated list of staff role IDs for this category",
|
||||||
|
"name": "roles"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"description": "Delete a category",
|
||||||
|
"name": "delete",
|
||||||
|
"options": {
|
||||||
|
"id": {
|
||||||
|
"description": "The ID of the category to delete",
|
||||||
|
"name": "id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"edit": {
|
||||||
|
"description": "Make changes to a category's configuration",
|
||||||
|
"name": "edit",
|
||||||
|
"options": {
|
||||||
|
"claiming": {
|
||||||
|
"description": "Enable ticket claiming?",
|
||||||
|
"name": "claiming"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "The ID of the category to edit",
|
||||||
|
"name": "id"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"description": "An image URL",
|
||||||
|
"name": "image"
|
||||||
|
},
|
||||||
|
"max_per_member": {
|
||||||
|
"description": "The maximum number of tickets a member can have in this category",
|
||||||
|
"name": "max_per_member"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"description": "The category name",
|
||||||
|
"name": "name"
|
||||||
|
},
|
||||||
|
"name_format": {
|
||||||
|
"description": "The ticket name format",
|
||||||
|
"name": "name_format"
|
||||||
|
},
|
||||||
|
"opening_message": {
|
||||||
|
"description": "The text to send when a ticket is opened",
|
||||||
|
"name": "opening_message"
|
||||||
|
},
|
||||||
|
"ping": {
|
||||||
|
"description": "A comma-separated list of role IDs to ping",
|
||||||
|
"name": "ping"
|
||||||
|
},
|
||||||
|
"require_topic": {
|
||||||
|
"description": "Require the user to give the topic of the ticket?",
|
||||||
|
"name": "require_topic"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"description": "A comma-separated list of staff role IDs",
|
||||||
|
"name": "roles"
|
||||||
|
},
|
||||||
|
"survey": {
|
||||||
|
"description": "The survey to use",
|
||||||
|
"name": "survey"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"description": "List categories",
|
||||||
|
"name": "list"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"set": {
|
||||||
|
"description": "Set options",
|
||||||
|
"name": "set",
|
||||||
|
"options": {
|
||||||
|
"close_button": {
|
||||||
|
"description": "Enable closing with a button?",
|
||||||
|
"name": "close_button"
|
||||||
|
},
|
||||||
|
"colour": {
|
||||||
|
"description": "The standard colour",
|
||||||
|
"name": "colour"
|
||||||
|
},
|
||||||
|
"error_colour": {
|
||||||
|
"description": "The error colour",
|
||||||
|
"name": "error_colour"
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"description": "The embed footer text",
|
||||||
|
"name": "footer"
|
||||||
|
},
|
||||||
|
"locale": {
|
||||||
|
"description": "The locale (language)",
|
||||||
|
"name": "locale"
|
||||||
|
},
|
||||||
|
"log_messages": {
|
||||||
|
"description": "Store messages from tickets?",
|
||||||
|
"name": "log_messages"
|
||||||
|
},
|
||||||
|
"success_colour": {
|
||||||
|
"description": "The success colour",
|
||||||
|
"name": "success_colour"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"invalid": "❌ Settings data is invalid; please refer to the documentation.\n%s",
|
"category_created": "✅ The `%s` ticket category has been created",
|
||||||
"updated": "✅ Settings have been updated."
|
"category_deleted": "✅ The `%s` ticket category has been deleted",
|
||||||
|
"category_does_not_exist": "❌ No category exists with the provided ID",
|
||||||
|
"category_updated": "✅ The `%s` ticket category has been updated",
|
||||||
|
"category_list": "Ticket categories",
|
||||||
|
"settings_updated": "✅ Settings have been updated"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"stats": {
|
"stats": {
|
||||||
@ -343,6 +465,7 @@
|
|||||||
"tickets": "Tickets"
|
"tickets": "Tickets"
|
||||||
},
|
},
|
||||||
"name": "stats",
|
"name": "stats",
|
||||||
|
"options": {},
|
||||||
"response": {
|
"response": {
|
||||||
"global": {
|
"global": {
|
||||||
"description": "Statistics about tickets across all guilds where this Discord TIckets instance is used.",
|
"description": "Statistics about tickets across all guilds where this Discord TIckets instance is used.",
|
||||||
@ -355,18 +478,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"survey": {
|
"survey": {
|
||||||
"aliases": {
|
"description": "View survey responses",
|
||||||
"surveys": "surveys"
|
"name": "survey",
|
||||||
},
|
"options": {
|
||||||
"args": {
|
|
||||||
"survey": {
|
"survey": {
|
||||||
"description": "The name of the survey to view responses of",
|
"description": "The name of the survey to view responses of",
|
||||||
"example": "support",
|
|
||||||
"name": "survey"
|
"name": "survey"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "View survey responses",
|
|
||||||
"name": "survey",
|
|
||||||
"response": {
|
"response": {
|
||||||
"list": {
|
"list": {
|
||||||
"title": "📃 Surveys"
|
"title": "📃 Surveys"
|
||||||
@ -374,20 +493,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tag": {
|
"tag": {
|
||||||
"aliases": {
|
"description": "Use a tag response",
|
||||||
"faq": "faq",
|
"name": "tag",
|
||||||
"t": "t",
|
"options": {
|
||||||
"tags": "tags"
|
|
||||||
},
|
|
||||||
"args": {
|
|
||||||
"tag": {
|
"tag": {
|
||||||
"description": "The name of the tag to use",
|
"description": "The name of the tag to use",
|
||||||
"example": "website",
|
|
||||||
"name": "tag"
|
"name": "tag"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Use a tag response",
|
|
||||||
"name": "tag",
|
|
||||||
"response": {
|
"response": {
|
||||||
"error": "❌ Error",
|
"error": "❌ Error",
|
||||||
"list": {
|
"list": {
|
||||||
@ -401,15 +514,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"topic": {
|
"topic": {
|
||||||
"args": {
|
"description": "Change the topic of the ticket",
|
||||||
|
"name": "topic",
|
||||||
|
"options": {
|
||||||
"new_topic": {
|
"new_topic": {
|
||||||
"description": "The new topic of the ticket",
|
"description": "The new topic of the ticket",
|
||||||
"example": "billing issue",
|
|
||||||
"name": "new_topic"
|
"name": "new_topic"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Change the topic of the ticket",
|
|
||||||
"name": "topic",
|
|
||||||
"response": {
|
"response": {
|
||||||
"changed": {
|
"changed": {
|
||||||
"description": "This ticket's topic has been changed.",
|
"description": "This ticket's topic has been changed.",
|
||||||
@ -422,24 +534,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"command_execution_error": {
|
|
||||||
"description": "An unexpected error occurred during command execution.\nPlease ask an administrator to check the console output / logs for details.",
|
|
||||||
"title": "⚠️"
|
|
||||||
},
|
|
||||||
"message_will_be_deleted_in": "This message will be deleted in %d seconds",
|
"message_will_be_deleted_in": "This message will be deleted in %d seconds",
|
||||||
"missing_permissions": {
|
"missing_permissions": {
|
||||||
"description": "You do not have the permissions required to use this command:\n%s",
|
"description": "You do not have the permissions required to use this command:\n%s",
|
||||||
"title": "❌"
|
"title": "❌ Error"
|
||||||
},
|
},
|
||||||
"staff_only": {
|
"panel": {
|
||||||
"description": "You must be a member of staff to use this command.",
|
"create_ticket": "Create a ticket"
|
||||||
"title": "❌"
|
|
||||||
},
|
},
|
||||||
"ticket": {
|
"ticket": {
|
||||||
|
"claim": "Claim",
|
||||||
"claimed": {
|
"claimed": {
|
||||||
"description": "%s has claimed this ticket.",
|
"description": "%s has claimed this ticket.",
|
||||||
"title": "✅ Ticket claimed"
|
"title": "✅ Ticket claimed"
|
||||||
},
|
},
|
||||||
|
"close": "Close",
|
||||||
"closed": {
|
"closed": {
|
||||||
"description": "This ticket has been closed.\nThe channel will be deleted in 5 seconds.",
|
"description": "This ticket has been closed.\nThe channel will be deleted in 5 seconds.",
|
||||||
"title": "✅ Ticket closed"
|
"title": "✅ Ticket closed"
|
||||||
@ -465,6 +574,7 @@
|
|||||||
"title": "Member removed"
|
"title": "Member removed"
|
||||||
},
|
},
|
||||||
"opening_message": {
|
"opening_message": {
|
||||||
|
"content": "%s\n%s has created a new ticket",
|
||||||
"fields": {
|
"fields": {
|
||||||
"topic": "Topic"
|
"topic": "Topic"
|
||||||
}
|
}
|
||||||
@ -483,6 +593,8 @@
|
|||||||
"description": "Hey, %s. Before this channel is deleted, would you mind completing a quick %d-question survey? React with ✅ to start, or ignore this message.",
|
"description": "Hey, %s. Before this channel is deleted, would you mind completing a quick %d-question survey? React with ✅ to start, or ignore this message.",
|
||||||
"title": "❔ Feedback"
|
"title": "❔ Feedback"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
"unclaim": "Release"
|
||||||
|
},
|
||||||
|
"updated_permissions": "✅ Slash command permissions updated"
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ const { path } = require('./utils/fs');
|
|||||||
const config = require('../user/config');
|
const config = require('../user/config');
|
||||||
const Logger = require('leekslazylogger');
|
const Logger = require('leekslazylogger');
|
||||||
module.exports = new Logger({
|
module.exports = new Logger({
|
||||||
debug: config.debug,
|
debug: config.developer.debug,
|
||||||
directory: path('./logs/'),
|
directory: path('./logs/'),
|
||||||
keepFor: config.logs.keep_for,
|
keepFor: config.logs.keep_for,
|
||||||
levels: {
|
levels: {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const {
|
const {
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Message, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
Interaction // eslint-disable-line no-unused-vars
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -9,11 +9,13 @@ const {
|
|||||||
module.exports = class Command {
|
module.exports = class Command {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @typedef CommandArgument
|
* @typedef CommandOption
|
||||||
* @property {string} name - The argument's name
|
* @property {string} name - The option's name
|
||||||
* @property {string} description - The argument's description
|
* @property {number} type - The option's type (use `Command.option_types`)
|
||||||
* @property {string} example - An example value
|
* @property {string} description - The option's description
|
||||||
* @property {boolean?} required - Is this arg required? Defaults to `false`
|
* @property {CommandOption[]} [options] - The option's options
|
||||||
|
* @property {(string|number)[]} [choices] - The option's choices
|
||||||
|
* @property {boolean} [required] - Is this arg required? Defaults to `false`
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Create a new Command
|
* Create a new Command
|
||||||
@ -23,8 +25,7 @@ module.exports = class Command {
|
|||||||
* @param {string} data.description - The description of the command (1-100)
|
* @param {string} data.description - The description of the command (1-100)
|
||||||
* @param {boolean} [data.staff_only] - Only allow staff to use this command?
|
* @param {boolean} [data.staff_only] - Only allow staff to use this command?
|
||||||
* @param {string[]} [data.permissions] - Array of permissions needed for a user to use this command
|
* @param {string[]} [data.permissions] - Array of permissions needed for a user to use this command
|
||||||
* @param {boolean} [data.process_args] - Should the command handler process named arguments?
|
* @param {CommandOption[]} [data.options] - The command's options
|
||||||
* @param {CommandArgument[]} [data.args] - The command's arguments (see [docs](https://github.com/75lb/command-line-args/blob/master/doc/option-definition.md) if using processed args)
|
|
||||||
*/
|
*/
|
||||||
constructor(client, data) {
|
constructor(client, data) {
|
||||||
|
|
||||||
@ -44,14 +45,6 @@ module.exports = class Command {
|
|||||||
*/
|
*/
|
||||||
this.name = data.name;
|
this.name = data.name;
|
||||||
|
|
||||||
/**
|
|
||||||
* The command's aliases
|
|
||||||
* @type {string[]}
|
|
||||||
*/
|
|
||||||
this.aliases = data.aliases ?? [];
|
|
||||||
|
|
||||||
if (!this.aliases.includes(this.name)) this.aliases.unshift(this.name);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The command description
|
* The command description
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@ -71,18 +64,11 @@ module.exports = class Command {
|
|||||||
*/
|
*/
|
||||||
this.permissions = data.permissions ?? [];
|
this.permissions = data.permissions ?? [];
|
||||||
|
|
||||||
/**
|
|
||||||
* Should the command handler process named arguments?
|
|
||||||
* @type {boolean}
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
this.process_args = data.process_args === true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The command options
|
* The command options
|
||||||
* @type {CommandArgument[]}
|
* @type {CommandOption[]}
|
||||||
*/
|
*/
|
||||||
this.args = data.args ?? [];
|
this.options = data.options ?? [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if command is internal, false if it is from a plugin
|
* True if command is internal, false if it is from a plugin
|
||||||
@ -100,64 +86,40 @@ module.exports = class Command {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
this.manager.register(this); // register the command
|
this.manager.register(this); // register the command
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
return this.client.log.error(e);
|
return this.client.log.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The code to be executed when a command is invoked
|
* The code to be executed when a command is invoked
|
||||||
* @abstract
|
* @abstract
|
||||||
* @param {Message} message - The message that invoked this command
|
* @param {Interaction} interaction - The message that invoked this command
|
||||||
* @param {(object|string)} [args] - Named command arguments, or the message content with the prefix and command removed
|
|
||||||
*/
|
*/
|
||||||
async execute(message, args) { } // eslint-disable-line no-unused-vars
|
async execute(interaction) { } // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
/**
|
async build(guild) {
|
||||||
* Send a message with the command usage
|
return {
|
||||||
* @param {TextChannel} channel - The channel to send the message to
|
defaultPermission: !this.staff_only,
|
||||||
* @param {string} [alias] - The command alias
|
description: this.description,
|
||||||
* @returns {Promise<Message>}
|
name: this.name,
|
||||||
*/
|
options: typeof this.options === 'function' ? await this.options(guild) : this.options
|
||||||
async sendUsage(channel, alias) {
|
|
||||||
const settings = await this.client.utils.getSettings(channel.guild);
|
|
||||||
if (!alias) alias = this.name;
|
|
||||||
|
|
||||||
const prefix = settings.command_prefix;
|
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
|
||||||
|
|
||||||
const addArgs = (embed, arg) => {
|
|
||||||
const required = arg.required ? '`❗` ' : '';
|
|
||||||
let description = `» ${i18n('cmd_usage.args.description', arg.description)}`;
|
|
||||||
if (arg.example) description += `\n» ${i18n('cmd_usage.args.example', arg.example)}`;
|
|
||||||
embed.addField(required + arg.name, description);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let usage,
|
|
||||||
example,
|
|
||||||
embed;
|
|
||||||
|
|
||||||
if (this.process_args) {
|
|
||||||
usage = `${prefix + alias} ${this.args.map(arg => arg.required ? `<${arg.name}>` : `[${arg.name}]`).join(' ')}`;
|
|
||||||
example = `${prefix + alias} \n${this.args.map(arg => `--${arg.name} ${arg.example || ''}`).join('\n')}`;
|
|
||||||
embed = new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setTitle(i18n('cmd_usage.title', alias))
|
|
||||||
.setDescription(i18n('cmd_usage.named_args') + i18n('cmd_usage.description', usage, example));
|
|
||||||
} else {
|
|
||||||
usage = `${prefix + alias} ${this.args.map(arg => arg.required ? `<${arg.name}>` : `[${arg.name}]`).join(' ')}`;
|
|
||||||
example = `${prefix + alias} ${this.args.map(arg => `${arg.example || ''}`).join(' ')}`;
|
|
||||||
embed = new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setTitle(i18n('cmd_usage.title', alias))
|
|
||||||
.setDescription(i18n('cmd_usage.description', usage, example));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.args.forEach(arg => addArgs(embed, arg));
|
static get option_types() {
|
||||||
return await channel.send({ embeds: [embed] });
|
return {
|
||||||
|
SUB_COMMAND: 1,
|
||||||
|
SUB_COMMAND_GROUP: 2,
|
||||||
|
STRING: 3, // eslint-disable-line sort-keys
|
||||||
|
INTEGER: 4, // eslint-disable-line sort-keys
|
||||||
|
BOOLEAN: 5, // eslint-disable-line sort-keys
|
||||||
|
USER: 6,
|
||||||
|
CHANNEL: 7, // eslint-disable-line sort-keys
|
||||||
|
ROLE: 8,
|
||||||
|
MENTIONABLE: 9, // eslint-disable-line sort-keys
|
||||||
|
NUMBER: 10
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
@ -2,16 +2,13 @@
|
|||||||
const {
|
const {
|
||||||
Client, // eslint-disable-line no-unused-vars
|
Client, // eslint-disable-line no-unused-vars
|
||||||
Collection,
|
Collection,
|
||||||
Message, // eslint-disable-line no-unused-vars
|
Interaction, // eslint-disable-line no-unused-vars
|
||||||
MessageEmbed
|
MessageEmbed
|
||||||
} = require('discord.js');
|
} = require('discord.js');
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { path } = require('../../utils/fs');
|
const { path } = require('../../utils/fs');
|
||||||
|
|
||||||
const { parseArgsStringToArgv: argv } = require('string-argv');
|
|
||||||
const parseArgs = require('command-line-args');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the loading and execution of commands
|
* Manages the loading and execution of commands
|
||||||
*/
|
*/
|
||||||
@ -48,81 +45,127 @@ module.exports = class CommandManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Register a command */
|
/** Register a command */
|
||||||
register(cmd) {
|
register(command) {
|
||||||
const exists = this.commands.has(cmd.name);
|
const exists = this.commands.has(command.name);
|
||||||
const is_internal = (exists && cmd.internal) || (exists && this.commands.get(cmd.name).internal);
|
const is_internal = (exists && command.internal) || (exists && this.commands.get(command.name).internal);
|
||||||
|
|
||||||
if (is_internal) {
|
if (is_internal) {
|
||||||
const plugin = this.client.plugins.plugins.find(p => p.commands.includes(cmd.name));
|
const plugin = this.client.plugins.plugins.find(p => p.commands.includes(command.name));
|
||||||
if (plugin) this.client.log.commands(`The "${plugin.name}" plugin has overridden the internal "${cmd.name}" command`);
|
if (plugin) this.client.log.commands(`The "${plugin.name}" plugin has overridden the internal "${command.name}" command`);
|
||||||
else this.client.log.commands(`An unknown plugin has overridden the internal "${cmd.name}" command`);
|
else this.client.log.commands(`An unknown plugin has overridden the internal "${command.name}" command`);
|
||||||
if(cmd.internal) return;
|
if(command.internal) return;
|
||||||
} else if (exists) {
|
} else if (exists) {
|
||||||
throw new Error(`A non-internal command with the name "${cmd.name}" already exists`);
|
throw new Error(`A non-internal command with the name "${command.name}" already exists`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.commands.set(cmd.name, cmd);
|
this.commands.set(command.name, command);
|
||||||
this.client.log.commands(`Loaded "${cmd.name}" command`);
|
this.client.log.commands(`Loaded "${command.name}" command`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async publish(guild) {
|
||||||
* Execute a command
|
if (!guild) {
|
||||||
* @param {Message} message - Command message
|
return this.client.guilds.cache.forEach(guild => {
|
||||||
*/
|
this.publish(guild);
|
||||||
async handle(message) {
|
});
|
||||||
if (message.author.bot) return; // ignore self and other bots
|
}
|
||||||
|
|
||||||
const settings = await this.client.utils.getSettings(message.guild);
|
try {
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const commands = await Promise.all(this.client.commands.commands.map(async command => await command.build(guild)));
|
||||||
const prefix = settings.command_prefix;
|
await this.client.application.commands.set(commands, guild.id);
|
||||||
const escaped_prefix = prefix.toLowerCase().replace(/(?=\W)/g, '\\'); // (lazy) escape every character so it can be used in a RexExp
|
await this.updatePermissions(guild);
|
||||||
const client_mention = `<@!?${this.client.user.id}>`;
|
this.client.log.success(`Published ${this.client.commands.commands.size} commands to "${guild.name}"`);
|
||||||
|
} catch (error) {
|
||||||
|
this.client.log.warn('An error occurred whilst publishing the commands');
|
||||||
|
this.client.log.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let cmd_name = message.content.match(new RegExp(`^(${escaped_prefix}|${client_mention}\\s?)(\\S+)`, 'mi')); // capture prefix and command
|
async updatePermissions(guild) {
|
||||||
if (!cmd_name) return; // stop here if the message is not a command
|
guild.commands.fetch().then(async commands => {
|
||||||
|
const permissions = [];
|
||||||
|
const settings = await this.client.utils.getSettings(guild.id);
|
||||||
|
const blacklist = [];
|
||||||
|
settings.blacklist.users?.forEach(userId => {
|
||||||
|
blacklist.push({
|
||||||
|
id: userId,
|
||||||
|
permission: false,
|
||||||
|
type: 'USER'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
settings.blacklist.roles?.forEach(roleId => {
|
||||||
|
blacklist.push({
|
||||||
|
id: roleId,
|
||||||
|
permission: false,
|
||||||
|
type: 'ROLE'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const raw_args = message.content.replace(cmd_name[0], '').trim(); // remove the prefix and command
|
const categories = await this.client.db.models.Category.findAll({ where: { guild: guild.id } });
|
||||||
cmd_name = cmd_name[2].toLowerCase(); // set cmd_name to the actual command alias, effectively removing the prefix
|
const staff_roles = new Set(categories.map(category => category.roles).flat());
|
||||||
|
|
||||||
const cmd = this.commands.find(cmd => cmd.aliases.includes(cmd_name));
|
commands.forEach(async g_cmd => {
|
||||||
if (!cmd) return;
|
const cmd_permissions = [...blacklist];
|
||||||
|
const command = this.client.commands.commands.get(g_cmd.name);
|
||||||
|
|
||||||
let is_blacklisted = false;
|
if (command.staff_only) {
|
||||||
if (settings.blacklist.includes(message.author.id)) {
|
cmd_permissions.push({
|
||||||
is_blacklisted = true;
|
id: guild.roles.everyone.id,
|
||||||
this.client.log.info(`Ignoring blacklisted member ${message.author.tag}`);
|
permission: false,
|
||||||
} else {
|
type: 'ROLE'
|
||||||
settings.blacklist.forEach(element => {
|
});
|
||||||
if (message.guild.roles.cache.has(element) && message.member.roles.cache.has(element)) {
|
staff_roles.forEach(roleId => {
|
||||||
is_blacklisted = true;
|
cmd_permissions.push({
|
||||||
this.client.log.info(`Ignoring member ${message.author.tag} with blacklisted role`);
|
id: roleId,
|
||||||
|
permission: true,
|
||||||
|
type: 'ROLE'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
permissions.push({
|
||||||
|
id: g_cmd.id,
|
||||||
|
permissions: cmd_permissions
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.client.log.debug(`Command permissions for "${guild.name}"`, require('util').inspect(permissions, {
|
||||||
|
colors: true,
|
||||||
|
depth: 10
|
||||||
|
}));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await guild.commands.permissions.set({ fullPermissions: permissions });
|
||||||
|
} catch (error) {
|
||||||
|
this.client.log.warn('An error occurred whilst updating command permissions');
|
||||||
|
this.client.log.error(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_blacklisted) {
|
/**
|
||||||
try {
|
* Execute a command
|
||||||
return message.react('❌');
|
* @param {Interaction} interaction - Command message
|
||||||
} catch (error) {
|
*/
|
||||||
return this.client.log.warn('Failed to react to a message');
|
async handle(interaction) {
|
||||||
}
|
if (!interaction.guild) return this.client.log.debug('Ignoring non-guild command interaction');
|
||||||
}
|
const settings = await this.client.utils.getSettings(interaction.guild.id);
|
||||||
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
const bot_permissions = message.guild.me.permissionsIn(message.channel);
|
const command = this.commands.get(interaction.commandName);
|
||||||
|
if (!command) return;
|
||||||
|
|
||||||
|
const bot_permissions = interaction.guild.me.permissionsIn(interaction.channel);
|
||||||
const required_bot_permissions = [
|
const required_bot_permissions = [
|
||||||
'ADD_REACTIONS',
|
|
||||||
'ATTACH_FILES',
|
'ATTACH_FILES',
|
||||||
'EMBED_LINKS',
|
'EMBED_LINKS',
|
||||||
'MANAGE_CHANNELS',
|
'MANAGE_CHANNELS',
|
||||||
'MANAGE_MESSAGES',
|
'MANAGE_MESSAGES'
|
||||||
'READ_MESSAGE_HISTORY',
|
|
||||||
'SEND_MESSAGES'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!bot_permissions.has(required_bot_permissions)) {
|
if (!bot_permissions.has(required_bot_permissions)) {
|
||||||
const perms = required_bot_permissions.map(p => `\`${p}\``).join(', ');
|
const perms = required_bot_permissions.map(p => `\`${p}\``).join(', ');
|
||||||
if (bot_permissions.has(['EMBED_LINKS', 'SEND_MESSAGES'])) {
|
if (bot_permissions.has('EMBED_LINKS')) {
|
||||||
await message.channel.send({
|
await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor('ORANGE')
|
.setColor('ORANGE')
|
||||||
@ -130,76 +173,33 @@ module.exports = class CommandManager {
|
|||||||
.setDescription(i18n('bot.missing_permissions.description', perms))
|
.setDescription(i18n('bot.missing_permissions.description', perms))
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
} else if (bot_permissions.has('SEND_MESSAGES')) {
|
|
||||||
await message.channel.send({ content: '⚠️ ' + i18n('bot.missing_permissions.description', perms) });
|
|
||||||
} else if (bot_permissions.has('ADD_REACTIONS')) {
|
|
||||||
await message.react('⚠️');
|
|
||||||
} else {
|
} else {
|
||||||
this.client.log.warn('Unable to respond to command due to missing permissions');
|
await interaction.reply({ content: i18n('bot.missing_permissions.description', perms) });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const missing_permissions = cmd.permissions instanceof Array && !message.member.permissions.has(cmd.permissions);
|
const missing_permissions = command.permissions instanceof Array && !interaction.member.permissions.has(command.permissions);
|
||||||
if (missing_permissions) {
|
if (missing_permissions) {
|
||||||
const perms = cmd.permissions.map(p => `\`${p}\``).join(', ');
|
const perms = command.permissions.map(p => `\`${p}\``).join(', ');
|
||||||
return await message.channel.send({
|
return await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.error_colour)
|
.setColor(settings.error_colour)
|
||||||
.setTitle(i18n('missing_permissions.title'))
|
.setTitle(i18n('missing_permissions.title'))
|
||||||
.setDescription(i18n('missing_permissions.description', perms))
|
.setDescription(i18n('missing_permissions.description', perms))
|
||||||
]
|
],
|
||||||
|
ephemeral: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd.staff_only && await this.client.utils.isStaff(message.member) === false) {
|
|
||||||
return await message.channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setTitle(i18n('staff_only.title'))
|
|
||||||
.setDescription(i18n('staff_only.description'))
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let args = raw_args;
|
|
||||||
|
|
||||||
if (cmd.process_args) {
|
|
||||||
try {
|
|
||||||
args = parseArgs(cmd.args, { argv: argv(raw_args) });
|
|
||||||
} catch (error) {
|
|
||||||
const help_cmd = `${settings.command_prefix}${i18n('commands.help.name')} ${cmd_name}`;
|
|
||||||
return await message.channel.send({
|
|
||||||
embeds: [
|
|
||||||
new MessageEmbed()
|
|
||||||
.setColor(settings.error_colour)
|
|
||||||
.setTitle(i18n('cmd_usage.invalid_named_args.title'))
|
|
||||||
.setDescription(i18n('cmd_usage.invalid_named_args.description', error.message, help_cmd))
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (const arg of cmd.args) {
|
|
||||||
if (arg.required && args[arg.name] === undefined) {
|
|
||||||
return await cmd.sendUsage(message.channel, cmd_name); // send usage if any required arg is missing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const args_num = raw_args.split(/\s/g).filter(arg => arg.length !== 0).length; // count the number of single-word args were given
|
|
||||||
const required_args = cmd.args.reduce((acc, arg) => arg.required ? acc + 1 : acc, 0); // count how many of the args are required
|
|
||||||
if (args_num < required_args) {
|
|
||||||
return await cmd.sendUsage(message.channel, cmd_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.client.log.commands(`Executing "${cmd.name}" command (invoked by ${message.author.tag})`);
|
this.client.log.commands(`Executing "${command.name}" command (invoked by ${interaction.user.tag})`);
|
||||||
await cmd.execute(message, args); // execute the command
|
await command.execute(interaction); // execute the command
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.client.log.warn(`An error occurred whilst executing the ${cmd.name} command`);
|
this.client.log.warn(`An error occurred whilst executing the ${command.name} command`);
|
||||||
this.client.log.error(e);
|
this.client.log.error(e);
|
||||||
await message.channel.send({
|
await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor('ORANGE')
|
.setColor('ORANGE')
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
/* eslint-disable max-lines */
|
/* eslint-disable max-lines */
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const TicketArchives = require('./archives');
|
const TicketArchives = require('./archives');
|
||||||
const { MessageEmbed } = require('discord.js');
|
const {
|
||||||
|
MessageActionRow,
|
||||||
|
MessageButton,
|
||||||
|
MessageEmbed
|
||||||
|
} = require('discord.js');
|
||||||
|
|
||||||
/** Manages tickets */
|
/** Manages tickets */
|
||||||
module.exports = class TicketManager extends EventEmitter {
|
module.exports = class TicketManager extends EventEmitter {
|
||||||
@ -70,23 +74,13 @@ module.exports = class TicketManager extends EventEmitter {
|
|||||||
});
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const settings = await this.client.utils.getSettings(guild);
|
const settings = await this.client.utils.getSettings(guild.id);
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
|
|
||||||
topic = t_row.topic
|
topic = t_row.topic
|
||||||
? this.client.cryptr.decrypt(t_row.topic)
|
? this.client.cryptr.decrypt(t_row.topic)
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
if (cat_row.ping instanceof Array && cat_row.ping.length > 0) {
|
|
||||||
const mentions = cat_row.ping.map(id => id === 'everyone'
|
|
||||||
? '@everyone'
|
|
||||||
: id === 'here'
|
|
||||||
? '@here'
|
|
||||||
: `<@&${id}>`);
|
|
||||||
|
|
||||||
await t_channel.send({ content: mentions.join(', ') });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cat_row.image) {
|
if (cat_row.image) {
|
||||||
await t_channel.send({ content: cat_row.image });
|
await t_channel.send({ content: cat_row.image });
|
||||||
}
|
}
|
||||||
@ -102,8 +96,39 @@ module.exports = class TicketManager extends EventEmitter {
|
|||||||
|
|
||||||
if (topic) embed.addField(i18n('ticket.opening_message.fields.topic'), topic);
|
if (topic) embed.addField(i18n('ticket.opening_message.fields.topic'), topic);
|
||||||
|
|
||||||
|
const components = new MessageActionRow();
|
||||||
|
|
||||||
|
if (cat_row.claiming) {
|
||||||
|
components.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId('ticket.claim')
|
||||||
|
.setLabel(i18n('ticket.claim'))
|
||||||
|
.setEmoji('🙌')
|
||||||
|
.setStyle('SECONDARY')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.close_button) {
|
||||||
|
components.addComponents(
|
||||||
|
new MessageButton()
|
||||||
|
.setCustomId('ticket.close')
|
||||||
|
.setLabel(i18n('ticket.close'))
|
||||||
|
.setEmoji('✖️')
|
||||||
|
.setStyle('DANGER')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mentions = cat_row.ping instanceof Array && cat_row.ping.length > 0
|
||||||
|
? cat_row.ping.map(id => id === 'everyone'
|
||||||
|
? '@everyone'
|
||||||
|
: id === 'here'
|
||||||
|
? '@here'
|
||||||
|
: `<@&${id}>`)
|
||||||
|
.join(', ')
|
||||||
|
: '';
|
||||||
const sent = await t_channel.send({
|
const sent = await t_channel.send({
|
||||||
content: creator.user.toString(),
|
components: [components],
|
||||||
|
content: i18n('ticket.opening_message.content', mentions, creator.user.toString()),
|
||||||
embeds: [embed]
|
embeds: [embed]
|
||||||
});
|
});
|
||||||
await sent.pin({ reason: 'Ticket opening message' });
|
await sent.pin({ reason: 'Ticket opening message' });
|
||||||
@ -118,10 +143,6 @@ module.exports = class TicketManager extends EventEmitter {
|
|||||||
.catch(() => this.client.log.warn('Failed to delete system pin message'));
|
.catch(() => this.client.log.warn('Failed to delete system pin message'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cat_row.claiming) {
|
|
||||||
await sent.react('🙌');
|
|
||||||
}
|
|
||||||
|
|
||||||
let questions;
|
let questions;
|
||||||
if (cat_row.opening_questions) {
|
if (cat_row.opening_questions) {
|
||||||
questions = cat_row.opening_questions
|
questions = cat_row.opening_questions
|
||||||
@ -134,7 +155,7 @@ module.exports = class TicketManager extends EventEmitter {
|
|||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setColor(settings.colour)
|
.setColor(settings.colour)
|
||||||
.setTitle('⚠️ ' + i18n('commands.new.request_topic.title'))
|
.setTitle(i18n('commands.new.request_topic.title'))
|
||||||
.setDescription(i18n('commands.new.request_topic.description'))
|
.setDescription(i18n('commands.new.request_topic.description'))
|
||||||
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 120)), guild.iconURL())
|
.setFooter(this.client.utils.footer(settings.footer, i18n('collector_expires_in', 120)), guild.iconURL())
|
||||||
]
|
]
|
||||||
@ -213,7 +234,7 @@ module.exports = class TicketManager extends EventEmitter {
|
|||||||
this.emit('beforeClose', ticket_id);
|
this.emit('beforeClose', ticket_id);
|
||||||
|
|
||||||
const guild = this.client.guilds.cache.get(t_row.guild);
|
const guild = this.client.guilds.cache.get(t_row.guild);
|
||||||
const settings = await this.client.utils.getSettings(guild);
|
const settings = await this.client.utils.getSettings(guild.id);
|
||||||
const i18n = this.client.i18n.getLocale(settings.locale);
|
const i18n = this.client.i18n.getLocale(settings.locale);
|
||||||
const channel = await this.client.channels.fetch(t_row.id);
|
const channel = await this.client.channels.fetch(t_row.id);
|
||||||
|
|
||||||
@ -273,10 +294,9 @@ module.exports = class TicketManager extends EventEmitter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (channel) {
|
if (channel) {
|
||||||
const creator = await guild.members.fetch(t_row.creator);
|
guild.members.fetch(t_row.creator)
|
||||||
|
.then(async creator => {
|
||||||
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
|
const cat_row = await this.client.db.models.Category.findOne({ where: { id: t_row.category } });
|
||||||
|
|
||||||
if (creator && cat_row.survey) {
|
if (creator && cat_row.survey) {
|
||||||
const survey = await this.client.db.models.Survey.findOne({
|
const survey = await this.client.db.models.Survey.findOne({
|
||||||
where: {
|
where: {
|
||||||
@ -365,6 +385,11 @@ module.exports = class TicketManager extends EventEmitter {
|
|||||||
} else {
|
} else {
|
||||||
await close();
|
await close();
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch(async () => {
|
||||||
|
this.client.log.debug('Skipping survey as member has left');
|
||||||
|
await close();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('close', ticket_id);
|
this.emit('close', ticket_id);
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
|
|
||||||
const {
|
const { GuildMember } = require('discord.js'); // eslint-disable-line no-unused-vars
|
||||||
Guild, // eslint-disable-line no-unused-vars
|
const { Model } = require('sequelize'); // eslint-disable-line no-unused-vars
|
||||||
GuildMember // eslint-disable-line no-unused-vars
|
|
||||||
} = require('discord.js');
|
|
||||||
const config = require('../../user/config');
|
const config = require('../../user/config');
|
||||||
let current_presence = -1;
|
let current_presence = -1;
|
||||||
|
|
||||||
@ -33,12 +31,12 @@ module.exports = class DiscordUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a guild's settings
|
* Fet a guild's settings
|
||||||
* @param {Guild} guild - The Guild
|
* @param {string} id - The guild's ID
|
||||||
* @returns {Promise<Model>}
|
* @returns {Promise<Model>}
|
||||||
*/
|
*/
|
||||||
async getSettings(guild) {
|
async getSettings(id) {
|
||||||
const data = { id: guild.id };
|
const data = { id };
|
||||||
const [settings] = await this.client.db.models.Guild.findOrCreate({
|
const [settings] = await this.client.db.models.Guild.findOrCreate({
|
||||||
defaults: data,
|
defaults: data,
|
||||||
where: data
|
where: data
|
||||||
@ -48,11 +46,11 @@ module.exports = class DiscordUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a guild's settings
|
* Delete a guild's settings
|
||||||
* @param {Guild} guild - The Guild
|
* @param {string} id - The guild ID
|
||||||
* @returns {Promise<Number>}
|
* @returns {Promise<Number>}
|
||||||
*/
|
*/
|
||||||
async deleteSettings(guild) {
|
async deleteSettings(id) {
|
||||||
const row = await this.getSettings(guild);
|
const row = await this.getSettings(id);
|
||||||
return await row.destroy();
|
return await row.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,17 +16,15 @@
|
|||||||
* ###############################################################################################
|
* ###############################################################################################
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const prefix = '-';
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
debug: false,
|
|
||||||
defaults: {
|
defaults: {
|
||||||
colour: '#009999',
|
colour: '#009999',
|
||||||
command_prefix: prefix,
|
|
||||||
log_messages: true,
|
log_messages: true,
|
||||||
name_format: 'ticket-{number}',
|
name_format: 'ticket-{number}',
|
||||||
opening_message: 'Hello {name}, thank you for creating a ticket. A member of staff will soon be available to assist you.\n\n__All messages in this channel are stored for future reference.__'
|
opening_message: 'Hello {name}, thank you for creating a ticket. A member of staff will soon be available to assist you.\n\n__All messages in this channel are stored for future reference.__'
|
||||||
},
|
},
|
||||||
|
developer: { debug: false },
|
||||||
locale: 'en-GB',
|
locale: 'en-GB',
|
||||||
logs: {
|
logs: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -39,7 +37,7 @@ module.exports = {
|
|||||||
duration: 60,
|
duration: 60,
|
||||||
presences: [
|
presences: [
|
||||||
{
|
{
|
||||||
activity: `${prefix}new`,
|
activity: '/new',
|
||||||
type: 'PLAYING'
|
type: 'PLAYING'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user