Solved merge conflicts

This commit is contained in:
JasperAtSchool
2026-05-20 10:42:17 +02:00
247 changed files with 10788 additions and 25817 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
# Contributing Guidelines # Contributing Guidelines
<img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="500px"> <img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="500px">
[![discord](https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) [![version](https://img.shields.io/badge/version-4.1.3-brightgreen.svg?style=flat-square)](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.3) [![Sponsor DJj123dj](https://img.shields.io/badge/sponsor-DJj123dj-ea4aaa?style=flat-square&logo=githubsponsors)](https://github.com/sponsors/DJj123dj) [![discord](https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) [![version](https://img.shields.io/badge/version-4.2.0-brightgreen.svg?style=flat-square)](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.2.0) [![Sponsor DJj123dj](https://img.shields.io/badge/sponsor-DJj123dj-ea4aaa?style=flat-square&logo=githubsponsors)](https://github.com/sponsors/DJj123dj)
These are the Contributing Guidelines of Open Ticket!<br> These are the Contributing Guidelines of Open Ticket!<br>
Here you can find everything you need to know about contributing to Open Ticket.<br> Here you can find everything you need to know about contributing to Open Ticket.<br>
+8 -11
View File
@@ -19,18 +19,15 @@ This list will be updated on every release.
| Version | Supported | Notes | | Version | Supported | Notes |
|------------|-----------|---------------------------------------------------------------| |------------|-----------|---------------------------------------------------------------|
| 4.2.0 | 🟦 | In Development | | 4.2.x | 🟦 | In Development |
| 4.1.x | 🟦 | In Development | | 4.2.1 | 🟦 | In Development |
| 4.1.3 | ✅ | | | 4.2.0 | ✅ | |
| 4.1.2 | ✅ | | | 4.1.3 | ✅ | (LTS) Long-Term-Support, Until September 2026 |
| 4.1.1 | ✅ | Supported Until April 2026 (LTS) | | 4.1.2 | 🚧 | |
| 4.1.1 | 🚧 | |
| 4.1.0 | 🚧 | | | 4.1.0 | 🚧 | |
| 4.0.7 | 🚧 | | | 4.0.7 | 🟧 | Deprecated |
| 4.0.6 | 🚧 | | | < 4.0.7 | ❌ | |
| 4.0.5 | 🟧 | Deprecated |
| 4.0.4 | 🟧 | Deprecated |
| < 4.0.4 | 🟧 | Deprecated, Transcripts v2.0, Documentation Only |
| < 4.0.0 | ❌ | |
### 🕷️ Reporting Vulnerabilities ### 🕷️ Reporting Vulnerabilities
You can report vulnerabilities, errors & bugs using one of the following methods: You can report vulnerabilities, errors & bugs using one of the following methods:
+8 -4
View File
@@ -17,7 +17,11 @@ otdebug.txt
*/*/*/.DS_Store */*/*/.DS_Store
**/.DS_Store **/.DS_Store
.docs/* .backup/*
!.docs/createDocs.js .tools/*
!.docs/mergeTranslations.js !.tools/createDocs.js
!.docs/typedoc-config.json !.tools/mergeTranslations.js
!.tools/typedoc-config.json
!.tools/pterodactyl-eggs/
!.tools/docker-compose.yml
!.tools/dockerfile
+2 -2
View File
@@ -1,6 +1,6 @@
# Docker File for Open Ticket v4 # Docker File for Open Ticket v4
# Use the official Node.js 20 image from Docker Hub # Use the official Node.js 22 image from Docker Hub
FROM node:20-alpine FROM node:22-alpine
# Set pterodactyl working directory inside the container # Set pterodactyl working directory inside the container
WORKDIR /home/container WORKDIR /home/container
@@ -2,7 +2,7 @@
<img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="500px"> <img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="500px">
[![discord](https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) [![discord](https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3)
[![version](https://img.shields.io/badge/version-4.1.3-brightgreen.svg?style=flat-square)](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.3) [![version](https://img.shields.io/badge/version-4.2.0-brightgreen.svg?style=flat-square)](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.2.0)
[![Sponsor DJj123dj](https://img.shields.io/badge/sponsor-DJj123dj-ea4aaa?style=flat-square&logo=githubsponsors)](https://github.com/sponsors/DJj123dj) [![Sponsor DJj123dj](https://img.shields.io/badge/sponsor-DJj123dj-ea4aaa?style=flat-square&logo=githubsponsors)](https://github.com/sponsors/DJj123dj)
[![Open Ticket supports Pterodactyl Eggs!](https://img.shields.io/badge/pterodactyl-supported-10539F?style=flat-square&logo=pterodactyl)](.eggs/README.md) [![Open Ticket supports Pterodactyl Eggs!](https://img.shields.io/badge/pterodactyl-supported-10539F?style=flat-square&logo=pterodactyl)](.eggs/README.md)
@@ -20,6 +20,9 @@ It's recommended to provide at least `1GB` of **Memory/RAM** and `5GB` of **disk
[**`openticket-egg-main.json` (Recommended)**](openticket-egg-main.json) [**`openticket-egg-main.json` (Recommended)**](openticket-egg-main.json)
- This egg will use the `main` branch of Open Ticket. - This egg will use the `main` branch of Open Ticket.
[**`openticket-egg-v4.2.0.json`**](openticket-egg-v4.2.0.json)
- This egg will always use Open Ticket `v4.2.0`. Open Ticket updates will not have an effect on this egg.
[**`openticket-egg-v4.1.3.json`**](openticket-egg-v4.1.3.json) [**`openticket-egg-v4.1.3.json`**](openticket-egg-v4.1.3.json)
- This egg will always use Open Ticket `v4.1.3`. Open Ticket updates will not have an effect on this egg. - This egg will always use Open Ticket `v4.1.3`. Open Ticket updates will not have an effect on this egg.
@@ -0,0 +1,62 @@
{
"_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO",
"meta": {
"version": "PTDL_v2",
"update_url": null
},
"exported_at": "2025-03-16T18:10:18+01:00",
"name": "Open Ticket (v4.2.0)",
"author": "support@dj-dj.be",
"description": "This is the official Pterodactyl egg for Open Ticket v4.2.0, the most advanced & customisable discord ticket bot that you will ever find! You can customise up to 300+ variables! This includes Html Transcripts, Advanced Plugins, Custom Embeds, Questions\/Modals, Stats & more!",
"features": null,
"docker_images": {
"ghcr.io\/parkervcp\/yolks:nodejs_20": "ghcr.io\/parkervcp\/yolks:nodejs_20"
},
"file_denylist": [],
"startup": "if [[ ! -z ${NODE_PACKAGES} ]]; then npm install ${NODE_PACKAGES}; fi; if [[ ! -z ${UNNODE_PACKAGES} ]]; then npm uninstall ${UNNODE_PACKAGES}; fi; if [ -f \/home\/container\/package.json ]; then npm install; fi; node \"\/home\/container\/index.js\" ${NODE_FLAGS};",
"config": {
"files": "{}",
"startup": "{\r\n \"done\": \"STARTUP INFO:\"\r\n}",
"logs": "{}",
"stop": "^C"
},
"scripts": {
"installation": {
"script": "#!\/bin\/bash\r\n# Open Ticket Installation Script (v4.2.0)\r\n# Inspired by: Node.js Installation Script\r\n# \u00a9 DJdj Development\r\n\r\necho -e \"[OT INSTALLER] installing dependencies. please wait...\"\r\napt update\r\napt install -y git curl\r\n\r\necho -e \"[OT INSTALLER] updating npm. please wait...\"\r\nnpm install npm@latest --location=global\r\n\r\nmkdir -p \/mnt\/server\r\ncd \/mnt\/server\r\n\r\nBRANCH=\"v4.2.0\"\r\n\r\nif [ \"$(ls -A \/mnt\/server)\" ]; then\r\n echo -e \"[OT INSTALLER] \/mnt\/server directory is not empty.\"\r\n if [ -d .git ]; then\r\n echo -e \"[OT INSTALLER] .git directory exists\"\r\n if [ -f .git\/config ]; then\r\n echo -e \"[OT INSTALLER] loading info from git config\"\r\n ORIGIN=$(git config --get remote.origin.url)\r\n else\r\n echo -e \"[OT INSTALLER] files found with no git config\"\r\n echo -e \"[OT INSTALLER] closing out without touching things to not break anything\"\r\n exit 10\r\n fi\r\n fi\r\n\r\n if [ \"${ORIGIN}\" == \"https:\/\/github.com\/open-discord-bots\/open-ticket.git\" ]; then\r\n echo \"pulling latest from github\"\r\n git pull\r\n fi\r\nelse\r\n echo -e \"[OT INSTALLER] \/mnt\/server is empty.\"\r\n echo -e \"[OT INSTALLER] cloning files into repo.\"\r\n if [ -z ${BRANCH} ]; then\r\n echo -e \"[OT INSTALLER] cloning default branch\"\r\n git clone https:\/\/github.com\/open-discord-bots\/open-ticket.git .\r\n else\r\n echo -e \"[OT INSTALLER] cloning ${BRANCH}'\"\r\n git clone --single-branch --branch ${BRANCH} https:\/\/github.com\/open-discord-bots\/open-ticket.git .\r\n fi\r\nfi\r\n\r\necho -e \"[OT INSTALLER] installing Open Ticket node.js packages.\"\r\nif [ -f \/mnt\/server\/package.json ]; then\r\n \/usr\/local\/bin\/npm install --omit=dev\r\nfi\r\n\r\necho -e \"[OT INSTALLER] installing custom node.js packages.\"\r\nif [[ ! -z ${NODE_PACKAGES} ]]; then\r\n \/usr\/local\/bin\/npm install ${NODE_PACKAGES}\r\nfi\r\n\r\necho -e \"[OT INSTALLER] install complete!\"\r\nexit 0",
"container": "node:latest",
"entrypoint": "bash"
}
},
"variables": [
{
"name": "Additional Npm Packages",
"description": "Specify additional npm packages used by Open Ticket plugins. Use spaces to separate.",
"env_variable": "NODE_PACKAGES",
"default_value": "",
"user_viewable": false,
"user_editable": true,
"rules": "string|nullable",
"field_type": "text"
},
{
"name": "Startup Flags",
"description": "Start the bot with additional Open Ticket flags. Separate using spaces.\r\nA full reference list can be found in the documentation.",
"env_variable": "NODE_FLAGS",
"default_value": "",
"user_viewable": false,
"user_editable": true,
"rules": "string|nullable",
"field_type": "text"
},
{
"name": "Uninstall Npm Packages",
"description": "A list of npm packages to uninstall. Separate by spaces.",
"env_variable": "UNNODE_PACKAGES",
"default_value": "",
"user_viewable": false,
"user_editable": true,
"rules": "string|nullable",
"field_type": "text"
}
]
}
+7 -7
View File
@@ -4,7 +4,7 @@
<sub align="center">Related Projects:</sub><br> <sub align="center">Related Projects:</sub><br>
<a href="https://odplugins.dj-dj.be"><img src="https://apis.dj-dj.be/cdn/opendiscord/logo.png" alt="Open Discord" height="55px"></a><br><br> <a href="https://odplugins.dj-dj.be"><img src="https://apis.dj-dj.be/cdn/opendiscord/logo.png" alt="Open Discord" height="55px"></a><br><br>
<a href="https://discord.com/invite/26vT9wt3n3"><img alt="Discord Invite Link" src="https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord"></img></a> <a href="https://discord.com/invite/26vT9wt3n3"><img alt="Discord Invite Link" src="https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord"></img></a>
<a href="https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.3"><img alt="Open Ticket Version" src="https://img.shields.io/badge/version-4.1.3-brightgreen.svg?style=flat-square"></img></a> <a href="https://github.com/open-discord-bots/open-ticket/releases/tag/v4.2.0"><img alt="Open Ticket Version" src="https://img.shields.io/badge/version-4.2.0-brightgreen.svg?style=flat-square"></img></a>
<a href="https://otdocs.dj-dj.be"><img alt="Open Ticket Documentation" src="https://img.shields.io/badge/discord.js-v14-CB3837.svg?style=flat-square&logo=npm"></img></a> <a href="https://otdocs.dj-dj.be"><img alt="Open Ticket Documentation" src="https://img.shields.io/badge/discord.js-v14-CB3837.svg?style=flat-square&logo=npm"></img></a>
<a href="https://github.com/open-discord-bots/open-ticket/blob/main/LICENSE"><img alt="Open Ticket License" src="https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square"></img></a> <a href="https://github.com/open-discord-bots/open-ticket/blob/main/LICENSE"><img alt="Open Ticket License" src="https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square"></img></a>
<a href="https://otdocs.dj-dj.be"><img alt="Open Ticket Stars" src="https://img.shields.io/github/stars/djj123dj/open-ticket?color=yellow&label=stars&logo=github&style=flat-square"></img></a> <a href="https://otdocs.dj-dj.be"><img alt="Open Ticket Stars" src="https://img.shields.io/github/stars/djj123dj/open-ticket?color=yellow&label=stars&logo=github&style=flat-square"></img></a>
@@ -17,7 +17,7 @@
<p align="center"> <p align="center">
Open Ticket is the most <b>advanced and customizable</b> Discord ticket bot available. With <b>350+ configurable settings</b>, you have full control over every aspect of your ticket system! Open Ticket is the most <b>advanced and customizable</b> Discord ticket bot available. With <b>350+ configurable settings</b>, you have full control over every aspect of your ticket system!
From <code>HTML transcripts</code> and <code>Advanced Plugins</code> to <code>Claiming & Pinning</code>, <code>Questions & Modals</code>, <code>Detailed Statistics</code>, and much more.<br><br> From <code>HTML transcripts</code> and <code>Advanced Plugins</code> to <code>Claiming & Pinning</code>, <code>Questions & Modals</code>, <code>Detailed Statistics</code>, and much more.<br><br>
The bot is fully translated into <b>36+ languages</b> and has been battle-tested in large Discord servers.<br> The bot is fully translated into <b>37+ languages</b> and has been battle-tested in large Discord servers.<br>
Need help or want to get involved? Feel free to join our <a href="https://discord.dj-dj.be"><b>Discord server</b></a>. Need help or want to get involved? Feel free to join our <a href="https://discord.dj-dj.be"><b>Discord server</b></a>.
</p> </p>
@@ -25,7 +25,7 @@ Need help or want to get involved? Feel free to join our <a href="https://discor
<p align="center"><sup>❤️ Love Open Ticket? <a href="https://github.com/sponsors/DJj123dj">Sponsorships</a> help fuel our HTML transcript servers and future features! ❤️</sup></p> <p align="center"><sup>❤️ Love Open Ticket? <a href="https://github.com/sponsors/DJj123dj">Sponsorships</a> help fuel our HTML transcript servers and future features! ❤️</sup></p>
--- ---
> **[-> Navigate to (⏱️ Quick Setup)](#️-quick-start-using-cli)** > **[-> Navigate to (⏱️ Quick Setup)](#️-quick-start-using-interactive-cli-tool)**
> **[-> Navigate to (📚 Documentation)](https://otdocs.dj-dj.be)** > **[-> Navigate to (📚 Documentation)](https://otdocs.dj-dj.be)**
> **[-> Navigate to (📞 Support Server)](https://discord.dj-dj.be)** > **[-> Navigate to (📞 Support Server)](https://discord.dj-dj.be)**
@@ -37,7 +37,7 @@ Need help or want to get involved? Feel free to join our <a href="https://discor
- **📈 Scalable** - Made to handle huge servers and has already been **tested in servers with 100k members.** - **📈 Scalable** - Made to handle huge servers and has already been **tested in servers with 100k members.**
- **📄 HTML Transcripts** - The **built-in HTML Transcripts Service** provides beautiful & easy-to-use transcripts. - **📄 HTML Transcripts** - The **built-in HTML Transcripts Service** provides beautiful & easy-to-use transcripts.
- **✅ Ticket Status** - Close, reopen, delete, claim, pin, rename or move tickets in your server. - **✅ Ticket Status** - Close, reopen, delete, claim, pin, rename or move tickets in your server.
- **🇬🇧 Translation** - Every message has been translated in more than **36 languages** by our community. - **🇬🇧 Translation** - Every message has been translated in more than **37 languages** by our community.
- **🎨 Customisation** - More than **200+ settings** are related to customisation & advanced features. - **🎨 Customisation** - More than **200+ settings** are related to customisation & advanced features.
- **🖥️ Interactions** - The bot has full support for buttons, dropdowns, slash/text commands & modals. - **🖥️ Interactions** - The bot has full support for buttons, dropdowns, slash/text commands & modals.
- **∞ Unlimited Possibilities** - Create an infinite amount of tickets, questions & panels. - **∞ Unlimited Possibilities** - Create an infinite amount of tickets, questions & panels.
@@ -134,14 +134,14 @@ A list of amazing people who have contributed or provided supported for **Open T
</table> </table>
### 💬 Translators ### 💬 Translators
With the amazing support of our translators, we've been able to translate Open Ticket in more than **36 languages**! With the amazing support of our translators, we've been able to translate Open Ticket in more than **37 languages**!
#### Categories: #### Categories:
- **🟢 Available** - **🟢 Available**
- **🤖 Partially Made Using AI** - **🤖 Partially Made Using AI**
- **🟠 Incomplete** - **🟠 Incomplete**
- **🔴 Unavailable/Outdated** - **🔴 Unavailable/Outdated**
|🔍 |Languages (36) |Maintainer (Github/Discord) | |🔍 |Languages (37) |Maintainer (Github/Discord) |
|----|---------------------|--------------------------------| |----|---------------------|--------------------------------|
|🟢 |🇬🇧 English |djj123dj | |🟢 |🇬🇧 English |djj123dj |
|🟢 |🇳🇱 Dutch |djj123dj | |🟢 |🇳🇱 Dutch |djj123dj |
@@ -167,6 +167,7 @@ With the amazing support of our translators, we've been able to translate Open T
|🟢 |🇮🇷 Persian |dysashop & zhavis | |🟢 |🇮🇷 Persian |dysashop & zhavis |
|🟢 |🇧🇩 Bengali |HanumeshGupta | |🟢 |🇧🇩 Bengali |HanumeshGupta |
|🟢 |❓ Catalan |guillee3 | |🟢 |❓ Catalan |guillee3 |
|🟢 |🇨🇳 Traditional Chinese|me.october |
|🤖 |🇪🇪 Estonian |iamnotmega | |🤖 |🇪🇪 Estonian |iamnotmega |
|🤖 |🇫🇮 Finnish |iamnotmega | |🤖 |🇫🇮 Finnish |iamnotmega |
|🤖 |🇯🇵 Japanese |HanumeshGupta | |🤖 |🇯🇵 Japanese |HanumeshGupta |
@@ -179,7 +180,6 @@ With the amazing support of our translators, we've been able to translate Open T
|🤖 |🇷🇺 Russian |NoOneNook | |🤖 |🇷🇺 Russian |NoOneNook |
|🤖 |🇱🇻 Latvian |NoOneNook | |🤖 |🇱🇻 Latvian |NoOneNook |
|🤖 |🇻🇳 Vietnamese |ngocdiep2006 | |🤖 |🇻🇳 Vietnamese |ngocdiep2006 |
|🔴 |🇨🇳 Traditional Chinese|[⭐ Contribute!](.github/CONTRIBUTING.md)|
<!--[⭐ Contribute!](.github/CONTRIBUTING.md) --> <!--[⭐ Contribute!](.github/CONTRIBUTING.md) -->
## ⭐️ Star History ## ⭐️ Star History
-125
View File
@@ -1,125 +0,0 @@
{
"_INFO":{
"support":"https://otdocs.dj-dj.be",
"discord":"https://discord.dj-dj.be",
"version":"open-ticket-v4.1.3"
},
"token":"insert your bot token here! (or leave empty when using 'tokenFromENV')",
"tokenFromENV":false,
"mainColor":"#f8ba00",
"language":"english",
"prefix":"!ticket ",
"serverId":"discord server id",
"globalAdmins":["discord role id"],
"slashCommands":true,
"textCommands":true,
"status":{
"enabled":true,
"type":"listening OR watching OR playing OR custom",
"mode":"online OR invisible OR idle OR dnd",
"text":"/help",
"state":"(additional text or leave empty)"
},
"system":{
"preferSlashOverText":true,
"sendErrorOnUnknownCommand":true,
"questionFieldsInCodeBlock":true,
"displayFieldsWithQuestions":false,
"showGlobalAdminsInPanelRoles":false,
"disableVerifyBars":false,
"useRedErrorEmbeds":true,
"alwaysShowReason":false,
"emojiStyle":"before (OR after OR double OR disabled)",
"pinEmoji":"📌",
"replyOnTicketCreation":true,
"replyOnReactionRole":true,
"askPriorityOnTicketCreation":false,
"removeParticipantsOnClose":false,
"disableAutocloseAfterReopen":true,
"autodeleteRequiresClosedTicket":true,
"adminOnlyDeleteWithoutTranscript":true,
"allowCloseBeforeMessage":false,
"allowCloseBeforeAdminMessage":true,
"useTranslatedConfigChecker":true,
"pinFirstTicketMessage":false,
"enableTicketClaimButtons":true,
"enableTicketCloseButtons":true,
"enableTicketPinButtons":true,
"enableTicketDeleteButtons":true,
"enableTicketActionWithReason":true,
"enableDeleteWithoutTranscript":true,
"logs":{
"enabled":false,
"channel":"discord channel id"
},
"limits":{
"enabled":true,
"globalMaximum":50,
"userMaximum":3
},
"channelTopic":{
"showOptionName":true,
"showOptionDescription":false,
"showOptionTopic":true,
"showPriority":false,
"showClosed":true,
"showClaimed":false,
"showPinned":false,
"showCreator":false,
"showParticipants":false
},
"permissions":{
"help":"everyone (OR admin OR none OR role id)",
"panel":"admin (OR everyone OR none OR role id)",
"ticket":"none (OR admin OR everyone OR role id)",
"close":"everyone (OR admin OR none OR role id)",
"delete":"admin (OR everyone OR none OR role id)",
"reopen":"everyone (OR admin OR none OR role id)",
"claim":"admin (OR everyone OR none OR role id)",
"unclaim":"admin (OR everyone OR none OR role id)",
"pin":"admin (OR everyone OR none OR role id)",
"unpin":"admin (OR everyone OR none OR role id)",
"move":"admin (OR everyone OR none OR role id)",
"rename":"admin (OR everyone OR none OR role id)",
"add":"admin (OR everyone OR none OR role id)",
"remove":"admin (OR everyone OR none OR role id)",
"blacklist":"admin (OR everyone OR none OR role id)",
"stats":"everyone (OR admin OR none OR role id)",
"clear":"admin (OR everyone OR none OR role id)",
"autoclose":"admin (OR everyone OR none OR role id)",
"autodelete":"admin (OR everyone OR none OR role id)",
"transfer":"admin (OR everyone OR none OR role id)",
"topic":"admin (OR everyone OR none OR role id)",
"priority":"admin (OR everyone OR none OR role id)"
},
"messages":{
"creation":{"dm":false,"logs":true},
"closing":{"dm":false,"logs":true},
"deleting":{"dm":false,"logs":true},
"reopening":{"dm":false,"logs":true},
"claiming":{"dm":false,"logs":true},
"pinning":{"dm":false,"logs":true},
"adding":{"dm":false,"logs":true},
"removing":{"dm":false,"logs":true},
"renaming":{"dm":false,"logs":true},
"moving":{"dm":false,"logs":true},
"blacklisting":{"dm":false,"logs":true},
"transferring":{"dm":false,"logs":true},
"topicChange":{"dm":false,"logs":true},
"priorityChange":{"dm":false,"logs":true},
"reactionRole":{"dm":false,"logs":true}
}
}
}
+175
View File
@@ -0,0 +1,175 @@
/*
* Hi there! Thank you for installing Open Ticket.
* ----------------------------------------------
* If you need any assistance with configuring the bot,
* feel free to use the documentation or join our Discord server:
* https://otdocs.dj-dj.be
* https://discord.dj-dj.be
* ----------------------------------------------
* SETUP:
* 1. Install the required dependencies using the command: "npm install"
* 2. Configure the bot in one of the following ways:
* a. (easy) Using the Quick Setup CLI Tool
* b. (difficult) Using the JSON files in `./config/`
*
* Start the Quick Setup CLI Tool using the command: "npm run setup"
* After configuration, start the bot using the command: "npm start"
*
* Good luck! DJj123dj & contributors
*/
{
"_CONFIG_VERSION":"open-ticket-v4.2.0",
/* Load the bot token from .env or the "token" field below. Leave "token" empty if using "tokenFromENV". */
"token":"INSERT_BOT_TOKEN",
"tokenFromENV":false,
"mainColor":"#f8ba00", //Hex color used in most embeds
"language":"english", //Visit README.md for list
"prefix":"!ticket ", //Prefix used in text commands
"serverId":"DISCORD_SERVER_ID",
"globalAdmins":["DISCORD_ROLE_ID"], //Have access to all commands
/* Enable/disable text or slash commands. */
"slashCommands":true,
"textCommands":true,
/* Configure the status of the bot. */
"status":{
"enabled":true,
"type":"listening", //Choices: listening, watching, playing, custom
"mode":"online", //Choices: online, invisible, idle, dnd
"text":"/help",
"state":"" //Additional text (Leave empty to disable)
},
/* Send ticket logs to a channel or in DM of the ticket creator. */
"logs":{
"enabled":false,
"channel":"DISCORD_CHANNEL_ID",
"logMessages":{
"creation":{"dm":false,"logs":true},
"closing":{"dm":false,"logs":true},
"deleting":{"dm":false,"logs":true},
"reopening":{"dm":false,"logs":true},
"claiming":{"dm":false,"logs":true},
"pinning":{"dm":false,"logs":true},
"adding":{"dm":false,"logs":true},
"removing":{"dm":false,"logs":true},
"renaming":{"dm":false,"logs":true},
"moving":{"dm":false,"logs":true},
"blacklisting":{"dm":false,"logs":true},
"transferring":{"dm":false,"logs":true},
"topicChange":{"dm":false,"logs":true},
"priorityChange":{"dm":false,"logs":true},
"reactionRole":{"dm":false,"logs":true}
}
},
/* A large collection of settings for the ticket system. */
"ticketSystem":{
"preferSlashOverText":true, //Show slashcmds in help menu's
"sendErrorOnUnknownCommand":true, //Send error when command not found
"questionFieldsInCodeBlock":true, //Put question answers in code blocks
"displayFieldsWithQuestions":false, //Display embed fields together with question answers
"showGlobalAdminsInPanelRoles":false, //Include "globalAdmins" in panel admin lists
"disableVerifyBars":false, //Disable the (❌/✅) buttons
"useRedErrorEmbeds":true, //Make errors embeds always red
"alwaysShowReason":false, //Show reason even if none is provided
"emojiStyle":"before", //The style of emoji's in embeds. Choices: before, after, double, disabled
"pinEmoji":"📌", //Channel emoji of pinned tickets (Leave empty to disable)
"closeEmoji":"🔒", //Channel emoji of closed tickets (Leave empty to disable)
"replyOnTicketCreation":true, //Reply with a msg when a ticket is created
"replyOnReactionRole":true, //Reply with a msg when a reaction role is used
"askPriorityOnTicketCreation":true, //Show a dropdown to select priority
"removeParticipantsOnClose":false, //Remove non-admins when ticket is closed
"disableAutocloseAfterReopen":true, //Disable autoclose after ticket got reopened
"autodeleteRequiresClosedTicket":true, //A ticket must be closed before autodelete works
"adminOnlyDeleteWithoutTranscript":true, //Only allow "globalAdmins" to delete a ticket without transcript
"allowCloseBeforeMessage":false, //Allow closing before a message is sent
"allowCloseBeforeAdminMessage":true, //Allow closing before an admin has sent a message
"useTranslatedConfigChecker":true, //Translate config errors in the console
"pinFirstTicketMessage":true, //Pin the ticket message to the channel
/* Enable/disable certain buttons & features of the bot. */
"enableTicketClaimButtons":true,
"enableTicketCloseButtons":true,
"enableTicketPinButtons":true,
"enableTicketDeleteButtons":true,
"enableTicketActionWithReason":true,
"enableDeleteWithoutTranscript":true, //Allow deleting tickets without transcript
"enableCreateTicketForOtherUser":true, //Allow creating tickets for other users
/* Set the maximum amount of simultaneous tickets. */
"limits":{
"enabled":true,
"globalMaximum":50,
"userMaximum":3
},
/* Choose which data is shown in the channel topic. */
"channelTopic":{
"showOptionName":true,
"showOptionDescription":false,
"showOptionTopic":true,
"showPriority":false,
"showClosed":true,
"showClaimed":false,
"showPinned":false,
"showCreator":false,
"showParticipants":false
},
/* Move closed tickets to a separate category. */
"closedCategory":{
"enabled":false,
"categoryId":"DISCORD_CATEGORY_ID"
},
/* Create tickets in a backup category when the original category exceeds 50 channels. */
"backupCategory":{
"enabled":false,
"categoryId":"DISCORD_CATEGORY_ID"
},
/* Move claimed tickets to a matching category of the user that claimed the ticket. Set to empty list [] to disable. */
"claimedCategories":[
{"user":"DISCORD_USER_ID","category":"DISCORD_CATEGORY_ID"}
]
},
/*
* Set permissions for each individual command, button or action.
* CHOICES:
* >> "none" -> Command disabled
* >> "everyone" -> Allowed for everyone
* >> "admin" -> Global & ticket admins only
* >> "DISCORD_ROLE_ID" -> Custom role only
*/
"permissions":{
"help":"everyone",
"panel":"admin",
"ticket":"none",
"close":"everyone",
"delete":"admin",
"reopen":"everyone",
"claim":"admin",
"unclaim":"admin",
"pin":"admin",
"unpin":"admin",
"move":"admin",
"rename":"admin",
"add":"admin",
"remove":"admin",
"blacklist":"admin",
"stats":"everyone",
"clear":"admin",
"autoclose":"admin",
"autodelete":"admin",
"transfer":"admin",
"topic":"admin",
"priority":"admin",
"transcripts":"admin"
}
}
-126
View File
@@ -1,126 +0,0 @@
[
{
"id":"example-ticket",
"name":"Question",
"description":"Create this ticket if you have a question! (or leave empty)",
"type":"ticket",
"button":{
"emoji":"🎫 (or leave empty)",
"label":"question (or leave empty)",
"color":"gray OR red OR green OR blue"
},
"ticketAdmins":["discord role id"],
"readonlyAdmins":["discord role id"],
"allowCreationByBlacklistedUsers":false,
"questions":["example-question-1","example-question-2"],
"channel":{
"prefix":"question-",
"suffix":"user-name OR user-id OR random-number OR random-hex OR counter-dynamic OR counter-fixed",
"category":"category id (or leave empty)",
"closedCategory":"category id (or leave empty)",
"backupCategory":"category id (or leave empty)",
"claimedCategory":[
{"user":"user id","category":"category id"}
],
"topic":"This is the topic of this ticket channel and is visible to everyone! (or leave empty)"
},
"dmMessage":{
"enabled":false,
"text":"Thank you for creating a ticket in our server! (or leave empty)",
"embed":{
"enabled":false,
"title":"Embed Title! (or leave empty)",
"description":"Description (or leave empty)",
"customColor":"#f8ab00 (or leave empty)",
"image":"https://www.example.com/image.png (or leave empty)",
"thumbnail":"https://www.example.com/image.png (or leave empty)",
"fields":[
{"name":"field name","value":"field value","inline":false}
],
"timestamp":false
}
},
"ticketMessage":{
"enabled":true,
"text":"",
"embed":{
"enabled":true,
"title":"Question Ticket",
"description":"Thank you for creating a 'Question' ticket in our server!\nOur support team will help you as soon as possible!",
"customColor":"#f8ab00 (or leave empty)",
"image":"https://www.example.com/image.png (or leave empty)",
"thumbnail":"https://www.example.com/image.png (or leave empty)",
"fields":[
{"name":"field name","value":"field value","inline":false}
],
"timestamp":false
},
"ping":{
"@here":true,
"@everyone":false,
"custom":["discord role id"]
}
},
"autoclose":{
"enableInactiveHours":false,
"inactiveHours":24,
"enableUserLeave":false,
"disableOnClaim":false
},
"autodelete":{
"enableInactiveDays":false,
"inactiveDays":7,
"enableUserLeave":false,
"disableOnClaim":false
},
"cooldown":{
"enabled":false,
"cooldownMinutes":10
},
"limits":{
"enabled":false,
"globalMaximum":20,
"userMaximum":3
},
"slowMode":{
"enabled":false,
"slowModeSeconds":20
}
},
{
"id":"example-website",
"name":"Website",
"description":"Go to our website.",
"type":"website",
"button":{
"emoji":"😃",
"label":"Visit our website"
},
"url":"https://www.dj-dj.be"
},
{
"id":"example-role",
"name":"Update Ping",
"description":"Click here to get notified on updates!",
"type":"role",
"button":{
"emoji":"📢",
"label":"Update Ping",
"color":"gray OR red OR green OR blue"
},
"roles":["discord role id"],
"mode":"add&remove OR remove OR add",
"removeRolesOnAdd":["discord role id"],
"addOnMemberJoin":false
}
]
+165
View File
@@ -0,0 +1,165 @@
/*
* OPEN TICKET BUTTON OPTIONS
* ----------------------------------------------
* Create customizable ticket, website, reaction-role or sub-panel button options.
* Up to 25 options can be added to each panel in (config/panels.jsonc)
* There are 4 types of options available: ticket, website, role, sub-panel
*
* TIP: Create new options by copying everything between and including the {...} brackets of an option. Paste it after the last option and make sure that they are seperated by a comma.
*/
[
{
/* A ticket option creates a button to open a ticket. */
"id":"example-ticket",
"name":"Question",
"description":"Want to tell us something? Create this ticket for general questions for our support team.", //Leave empty to disable
"type":"ticket",
"button":{
/* Configure the button style of this option. At least one of "emoji" or "label" must be provided. */
"emoji":"🎫",
"label":"Question",
"color":"gray" //Choices: gray, red, green, blue
},
/* Add up to 5 modal questions IDs from (config/questions.jsonc). */
"questions":["example-question-1","example-question-2"],
"ticketAdmins":["DISCORD_ROLE_ID"],
"readonlyAdmins":["DISCORD_ROLE_ID"],
"allowCreationByBlacklistedUsers":false,
"channel":{
/* Configure the name, topic and category of the ticket option. */
"prefix":"question-",
"suffix":"user-name", //Choices: user-name, user-id, random-number, random-hex, counter-dynamic, counter-fixed
"category":"DISCORD_CATEGORY_ID", //Leave empty to disable
"topic":"The ticket topic shown in the channel." //Leave empty to disable
},
"dmMessage":{
/* Send a customisable message in DM when creating a ticket. */
"enabled":false,
"text":"", //Leave empty to disable
"embed":{
"enabled":false,
"title":"Question Ticket", //Leave empty to disable
"description":"Thank you for creating a ticket in our server. We will try to help you as soon as possible.", //Leave empty to disable
"customColor":"#f8ab00", //Leave empty to use default color
"image":"", //Image URL. Leave empty to disable
"thumbnail":"", //Image URL. Leave empty to disable
/* Embed fields. Set to empty list [] to disable. */
"fields":[
{"name":"Field name","value":"Field value","inline":false}
],
"timestamp":false
}
},
"ticketMessage":{
/* Send a customisable message in the ticket with close, claim, delete, ... buttons. */
"enabled":true,
"text":"", //Leave empty to disable
"embed":{
"enabled":true,
"title":"Question Ticket", //Leave empty to disable
"description":"Thank you for creating a ticket in our server.\nOur support team will assist you as soon as possible. (leave empty to disable)", //Leave empty to disable
"customColor":"#f8ab00 (leave empty to disable)", //Leave empty to use default color
"image":"https://www.example.com/image.png (leave empty to disable)", //Image URL. Leave empty to disable
"thumbnail":"https://www.example.com/image.png (leave empty to disable)", //Image URL. Leave empty to disable
/* Embed fields. Set to empty list [] to disable. */
"fields":[
{"name":"Field name","value":"Field value","inline":false}
],
"timestamp":false
},
"ping":{
/* Customise the user & role mentions of this ticket message. */
"@here":true,
"@everyone":false,
"custom":["DISCORD_ROLE_ID"]
}
},
"autoclose":{
/* Autoclose this ticket after a period of inactivity or when the creator leaves the server. */
"enableInactiveHours":false,
"inactiveHours":24,
"enableUserLeave":false,
"disableOnClaim":false
},
"autodelete":{
/* Autodelete this ticket after a period of inactivity or when the creator leaves the server. */
"enableInactiveDays":false,
"inactiveDays":7,
"enableUserLeave":false,
"disableOnClaim":false
},
"cooldown":{
/* Users must wait a certain period before being able to create another ticket of this type. */
"enabled":false,
"cooldownMinutes":10
},
"limits":{
/* Set the maximum amount of simultaneous tickets of this option. */
"enabled":false,
"globalMaximum":20,
"userMaximum":3
},
"slowMode":{
/* Enable slow-mode in the ticket channel. */
"enabled":false,
"slowModeSeconds":20
}
},
{
/* A website option creates a button with a URL to an external website. */
"id":"example-website",
"name":"Website",
"description":"Take a look at our amazing website.", //Leave empty to disable
"type":"website",
"button":{
/* Configure the button style of this option. At least one of "emoji" or "label" must be provided. */
"emoji":"😃",
"label":"Visit Website"
},
"url":"https://www.dj-dj.be"
},
{
/* A reaction-role option creates a button for members to choose roles. */
"id":"example-role",
"name":"Update Ping",
"description":"Receive notifications about updates in our server.", //Leave empty to disable
"type":"role",
"button":{
/* Configure the button style of this option. At least one of "emoji" or "label" must be provided. */
"emoji":"📢",
"label":"Update Ping",
"color":"gray" //Choices: gray, red, green, blue
},
"roles":["DISCORD_ROLE_ID"],
"mode":"add&remove OR remove OR add", //What to do with the roles. Choices: add&remove, add, remove
"removeRolesOnAdd":["DISCORD_ROLE_ID"], //Remove these old roles when new roles are added.
"addOnMemberJoin":false //Add these roles automatically when joining the server.
},
{
/* A sub-panel option creates a button which sends another panel for additional options. */
"id":"example-sub-panel",
"name":"Example Sub-Panel",
"description":"This is an example of how to implement a sub-panel in Open Ticket.", //Leave empty to disable
"type":"sub-panel",
"button":{
/* Configure the button style of this option. At least one of "emoji" or "label" must be provided. */
"emoji":"📋",
"label":"Sub-Panel Example",
"color":"gray" //Choices: gray, red, green, blue
},
"subPanelId":"example-panel" //Choose a panel ID from (config/panels.jsonc)
}
]
-39
View File
@@ -1,39 +0,0 @@
[
{
"id":"example-embed",
"name":"Example Embed",
"dropdown":false,
"options":["example-ticket","example-website","example-role"],
"text":"",
"embed":{
"enabled":true,
"title":"Tickets:",
"description":"Create a ticket by clicking one of the buttons below!",
"customColor":"#f8ab00 (or leave empty)",
"url":"https://openticket.dj-dj.be (or leave empty)",
"image":"https://www.example.com/image.png (or leave empty)",
"thumbnail":"https://www.example.com/image.png (or leave empty)",
"footer":"Open Ticket v4.1.3 (or leave empty)",
"fields":[
{"name":"field name","value":"field value","inline":false}
],
"timestamp":false
},
"settings":{
"dropdownPlaceholder":"Create a ticket!",
"enableMaxTicketsWarningInText":false,
"enableMaxTicketsWarningInEmbed":true,
"describeOptionsLayout":"simple OR normal OR detailed",
"describeOptionsCustomTitle":"",
"describeOptionsInText":false,
"describeOptionsInEmbedFields":true,
"describeOptionsInEmbedDescription":false
}
}
]
+57
View File
@@ -0,0 +1,57 @@
/*
* OPEN TICKET PANELS
* ----------------------------------------------
* Create customizable panel messages with buttons or a dropdown.
* Add up to 25 options to this panel from (config/options.jsonc)
* Panels can be customised with text, images, colors and more.
*
* Spawn the panel in Discord using: /panel <id>
*
* TIP: Create new panels by copying everything between and including the {...} brackets of an panel. Paste it after the last panel and make sure that they are seperated by a comma.
*/
[
{
/* A panel is creates a message with up to 25 options as buttons or dropdown. */
"id":"example-panel",
"name":"Example Panel",
"dropdown":false,
/* Add up to 5 option IDs from (config/options.jsonc). */
"options":["example-ticket","example-website","example-role"],
"text":"", //Leave empty to disable
"embed":{
"enabled":true,
"title":"Tickets:", //Leave empty to disable
"description":"Create a ticket by selecting one of the options below. Once selected, a private ticket will be created for you and our support team will be able to assist you directly.", //Leave empty to disable
"customColor":"#f8ab00", //Leave empty to use default color
"url":"", //URL. Leave empty to disable
"image":"", //Image URL. Leave empty to disable
"thumbnail":"", //Image URL. Leave empty to disable
"footer":"Open Ticket v4.2.0", //Leave empty to disable
/* Embed fields. Set to empty list [] to disable. */
"fields":[
{"name":"Field name","value":"Field value","inline":false}
],
"timestamp":false
},
"settings":{
"dropdownPlaceholder":"Create a ticket...", //Leave empty to use default.
"maximumButtonsPerRow":5,
/* Display the maximum amount of tickets per user. */
"enableMaxTicketsWarningInText":false,
"enableMaxTicketsWarningInEmbed":true,
/* Automatically generate option descriptions from (config/options.jsonc). */
"describeOptionsLayout":"normal", //Choices: simple, normal, detailed
"describeOptionsCustomTitle":"",
"describeOptionsInText":false,
"describeOptionsInEmbedFields":true,
"describeOptionsInEmbedDescription":false
}
}
]
-28
View File
@@ -1,28 +0,0 @@
[
{
"id":"example-question-1",
"name":"Example Question 1",
"type":"short",
"required":true,
"placeholder":"Insert your short answer here!",
"length":{
"enabled":false,
"min":0,
"max":1000
}
},
{
"id":"example-question-2",
"name":"Example Question 2",
"type":"paragraph",
"required":false,
"placeholder":"Insert your long answer here!",
"length":{
"enabled":false,
"min":0,
"max":1000
}
}
]
+102
View File
@@ -0,0 +1,102 @@
/*
* OPEN TICKET MODAL QUESTIONS
* ----------------------------------------------
* Create customizable modal questions that will be shown before creating a ticket.
* Each ticket option (config/options.jsonc) can contain a maximum of 5 questions.
* There are 6 types of questions available: short, paragraph, dropdown, radio-select, checkbox-select, text-display
*
* TIP: Create new questions by copying everything between and including the {...} brackets of a question. Paste it after the last question and make sure that they are seperated by a comma.
*/
[
{
/* A short text input modal question. */
"id":"example-question-1",
"name":"Example Question 1",
"description":"", //Leave empty to disable
"type":"short",
"required":true,
"placeholder":"Insert answer...",
"length":{
/* Configure length limits for the answer. */
"enabled":false,
"min":0,
"max":1000
}
},
{
/* A paragraph text input modal question. */
"id":"example-question-2",
"name":"Example Question 2",
"description":"", //Leave empty to disable
"type":"paragraph",
"required":false,
"placeholder":"Insert answer...",
"length":{
/* Configure length limits for the answer. */
"enabled":false,
"min":0,
"max":1000
}
},
{
/* A dropdown menu input modal question with up to 25 choices. "emoji" & "description" fields are optional. */
"id":"example-question-3",
"name":"Example Question 3",
"description":"This is a dropdown question.", //Leave empty to disable
"type":"dropdown",
"required":false,
"placeholder":"Choose your answer...",
"choices":[
{"title":"Choice A","description":"Apple","emoji":"🍎"},
{"title":"Choice B","description":"Banana","emoji":"🍌"},
{"title":"Choice C","description":"Orange","emoji":"🍊"},
{"title":"Choice D","description":"Kiwi","emoji":"🥝"}
]
},
{
/* A radio select input modal question with up to 10 choices. */
"id":"example-question-4",
"name":"Example Question 4",
"description":"This is a radio select question.", //Leave empty to disable
"type":"radio-select",
"required":true,
"choices":[
{"title":"Choice A","description":"Up","selectedByDefault":false},
{"title":"Choice B","description":"Down","selectedByDefault":false},
{"title":"Choice C","description":"Left","selectedByDefault":false},
{"title":"Choice D","description":"Right","selectedByDefault":false}
]
},
{
/* A checkbox select input modal question with up to 10 choices. */
"id":"example-question-5",
"name":"Example Question 5",
"description":"This is a checkbox select question.", //Leave empty to disable
"type":"checkbox-select",
"required":true,
"limits":{
/* Configure checkbox amount limits for the answer. */
"enabled":false,
"min":0,
"max":10
},
"choices":[
{"title":"Choice A","description":"Happiness","selectedByDefault":false},
{"title":"Choice B","description":"Anger","selectedByDefault":false},
{"title":"Choice C","description":"Sadness","selectedByDefault":false},
{"title":"Choice D","description":"Fear","selectedByDefault":false}
]
},
{
/* Show text in a modal to provide extra details or explain questions. */
"id":"example-text-display",
"type":"text-display",
"textContents":"This is a text display. It isn't a question, but allows you to display additional details."
}
]
-55
View File
@@ -1,55 +0,0 @@
{
"general":{
"enabled":false,
"enableChannel":false,
"enableCreatorDM":false,
"enableParticipantDM":false,
"enableActiveAdminDM":false,
"enableEveryAdminDM":false,
"channel":"transcript channel id (or leave empty)",
"mode":"html OR text"
},
"embedSettings":{
"customColor":"#f8ab00 (or leave empty)",
"listAllParticipants":false,
"includeTicketStats":false
},
"textTranscriptStyle":{
"layout":"simple OR normal OR detailed",
"includeStats":true,
"includeIds":false,
"includeEmbeds":true,
"includeFiles":true,
"includeBotMessages":true,
"fileMode":"custom OR channel-name OR channel-id OR user-name OR user-id",
"customFileName":"this-is-a-transcript (or leave empty)"
},
"htmlTranscriptStyle":{
"background":{
"enableCustomBackground":false,
"backgroundColor":"#f8ba00 (or leave empty)",
"backgroundImage":"https://www.example.com/image.png (or leave empty)"
},
"header":{
"enableCustomHeader":false,
"backgroundColor":"#202225",
"decoColor":"#f8ba00",
"textColor":"#ffffff"
},
"stats":{
"enableCustomStats":false,
"backgroundColor":"#202225",
"keyTextColor":"#737373",
"valueTextColor":"#ffffff",
"hideBackgroundColor":"#40444a",
"hideTextColor":"#ffffff"
},
"favicon":{
"enableCustomFavicon":false,
"imageUrl":"https://t.dj-dj.be/favicon.png"
}
}
}
+70
View File
@@ -0,0 +1,70 @@
/*
* OPEN TICKET TRANSCRIPTS
* ----------------------------------------------
* Enable transcript creation when tickets are deleted. There are 2 available transcript types: HTML & Text
*
* HTML Transcripts (recommended):
* Generate transcripts as HTML files to view in the browser. No server or domain required. HTML Transcripts use an external service to process and host the transcripts.
*
* Text Transcripts:
* Generate transcripts as simple .txt files with limited details. Processing happens fully local.
*/
{
"general":{
"enabled":false,
/* Choose which users and channel get the generated transcript. */
"enableChannel":false,
"enableCreatorDM":false,
"enableParticipantDM":false,
"enableActiveAdminDM":false,
"enableEveryAdminDM":false,
"channel":"DISCORD_CHANNEL_ID", //Where to send transcripts. Leave empty when disabled.
"mode":"html" //The type of transcript to use. Choices: html, text
},
"embedSettings":{
/* Customise the embed which contains the generated transcript file or URL. */
"customColor":"#f8ab00", //Leave empty to use default color
"listAllParticipants":false,
"includeTicketStats":false
},
"textTranscriptStyle":{
/* Customise layout of the text transcripts. */
"layout":"normal", //Choices: simple, normal, detailed
"includeStats":true,
"includeIds":false,
"includeEmbeds":true,
"includeFiles":true,
"includeBotMessages":true,
"fileMode":"custom", //How to name the transcript file? Choices: custom, channel-name, channel-id, user-name, user-id
"customFileName":"transcript" //Custom filename without extension
},
"htmlTranscriptStyle":{
/* Customise layout of the HTML transcripts. */
"background":{
"enableCustomBackground":false,
"backgroundColor":"#f8ba00", //Leave empty to use Open Ticket color (#f8ba00)
"backgroundImage":"https://www.example.com/image.png" //Image URL to fill entire background. Leave empty to disable
},
"header":{
"enableCustomHeader":false,
"backgroundColor":"#202225",
"decoColor":"#f8ba00",
"textColor":"#ffffff"
},
"stats":{
"enableCustomStats":false,
"backgroundColor":"#202225",
"keyTextColor":"#737373",
"valueTextColor":"#ffffff",
"hideBackgroundColor":"#40444a",
"hideTextColor":"#ffffff"
},
"favicon":{
"enableCustomFavicon":false,
"imageUrl":"https://t.dj-dj.be/favicon.png"
}
}
}
+1
View File
@@ -0,0 +1 @@
[]
+6 -158
View File
@@ -4,7 +4,6 @@ const flags = [
//PTERODACTYL PANEL //PTERODACTYL PANEL
//add startup flags here (e.g. "--no-compile") when running via the panel //add startup flags here (e.g. "--no-compile") when running via the panel
] ]
process.argv.push(...flags)
/////////////// STARTUP FLAGS /////////////// /////////////// STARTUP FLAGS ///////////////
/* /*
@@ -14,170 +13,19 @@ process.argv.push(...flags)
██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██║██║ ██╔═██╗ ██╔══╝ ██║ ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██║██║ ██╔═██╗ ██╔══╝ ██║
╚██████╔╝██║ ███████╗██║ ╚████║ ██║ ██║╚██████╗██║ ██╗███████╗ ██║ ╚██████╔╝██║ ███████╗██║ ╚████║ ██║ ██║╚██████╗██║ ██╗███████╗ ██║
╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝
v4.1.3 - Made by DJj123dj & Contributors v4.2.0 - Made by DJj123dj & Contributors
Discord: https://discord.dj-dj.be Discord: https://discord.dj-dj.be
Docs: https://otdocs.dj-dj.be Docs: https://otdocs.dj-dj.be
Support Us: https://github.com/sponsors/DJj123dj/ Support Us: https://github.com/sponsors/DJj123dj/
*/ */
/////////////////////////////////////////// ///////////////////////////////////////////
////////// COMPILATION + STARTUP ////////// ////////// COMPILATION + STARTUP //////////
/////////////////////////////////////////// ///////////////////////////////////////////
const fs = require("fs")
const ts = require("typescript")
const {createHash,Hash} = require("crypto")
const nodepath = require('path')
const ansis = require("ansis")
/** ## What is this? import { frameworkStartup } from "@open-discord-bots/framework"
* This is a function which compares `./src/` with a hash stored in `./dist/hash.txt`. frameworkStartup(flags,"openticket",async () => {
* The hash is based on the modified date & file metadata of all files in `./src/`. await import("./dist/src/index.js")
* })
* If the hash is different, the bot will automatically re-compile.
* This will help you save CPU resources because the bot shouldn't re-compile when nothing has been changed :)
*
* @param {string} dir
* @param {Hash|null} upperHash
*/
function computeSourceHash(dir,upperHash){
const hash = upperHash ? upperHash : createHash("sha256")
const info = fs.readdirSync(dir,{withFileTypes:true})
for (const file of info) {
const fullPath = nodepath.join(dir,file.name)
if (file.isFile() && [".js",".ts",".jsx",".tsx"].some((ext) => file.name.endsWith(ext))){
const statInfo = fs.statSync(fullPath)
//compute hash using file metadata
const fileInfo = `${fullPath}:${statInfo.size}:${statInfo.mtimeMs}`
hash.update(fileInfo)
}else if (file.isDirectory()){
//recursively compute all folders
computeSourceHash(fullPath,hash)
}
}
//return when not being called recursively
if (!upperHash) {
return hash.digest("hex")
}
}
function requiresCompilation(){
//check hashes when not using "--compile-only" flag
if (process.argv.includes("--compile-only")) return true
console.log("OT: Comparing prebuilds with source...")
const sourceHash = computeSourceHash("./src/")
const pluginHash = computeSourceHash("./plugins/")
const hash = sourceHash+":"+pluginHash
if (fs.existsSync("./dist/hash.txt")){
const distHash = fs.readFileSync("./dist/hash.txt").toString()
if (distHash === hash) return false
else return true
}else return true
}
function saveNewCompilationHash(){
const sourceHash = computeSourceHash("./src/")
const pluginHash = computeSourceHash("./plugins/")
const hash = sourceHash+":"+pluginHash
fs.writeFileSync("./dist/hash.txt",hash)
}
if (!process.argv.includes("--no-compile")){
const requiredDependencies = new Set()
if (fs.existsSync("./plugins")){
console.log("OT: Reading plugin.json files...")
for (const pluginDir of fs.readdirSync("./plugins")){
if (pluginDir === ".DS_Store") continue
const pluginPath = nodepath.join("./plugins", pluginDir)
if (!fs.statSync(pluginPath).isDirectory()) continue
const pluginJsonPath = nodepath.join(pluginPath, "plugin.json")
if (fs.existsSync(pluginJsonPath)){
try{
const pluginData = JSON.parse(fs.readFileSync(pluginJsonPath).toString())
if (pluginData.npmDependencies && Array.isArray(pluginData.npmDependencies)){
pluginData.npmDependencies.forEach((dep) => {
if (typeof dep === "string" && dep.trim()){
requiredDependencies.add(dep.trim())
}
})
}
}catch(err){
// skip invalid plugin.json files, will be caught later
}
}
}
if (requiredDependencies.size > 0){
console.log("OT: Checking plugin npm dependencies...")
/**@type {string[]} */
const missingDeps = []
for (const dep of requiredDependencies){
try{
require.resolve(dep)
}catch(err){
missingDeps.push(dep)
}
}
if (missingDeps.length > 0){
console.log(ansis.red("OT: ❌ Fatal Error --> Missing npm dependencies required by plugins:\n\n")+ansis.cyan(missingDeps.map((dep) => " - "+dep).join("\n")+"\n"))
console.log("OT: Please install missing dependencies using the following command:\n> "+ansis.bold.green("npm install " + missingDeps.join(" "))+"\n")
process.exit(1)
}
}
}
if (requiresCompilation()){
console.log("OT: Compilation Required...")
//REMOVE EXISTING BUILDS
console.log("OT: Removing Prebuilds...")
fs.rmSync("./dist",{recursive:true,force:true})
//COMPILE TYPESCRIPT
console.log("OT: Compiling Typescript...")
const configPath = nodepath.resolve('./tsconfig.json')
const configFile = ts.readConfigFile(configPath,ts.sys.readFile)
//check for tsconfig errors
if (configFile.error){
const message = ts.formatDiagnosticsWithColorAndContext([configFile.error],ts.createCompilerHost({}))
console.error(message)
process.exit(1)
}
//parse tsconfig file
const parsedConfig = ts.parseJsonConfigFileContent(configFile.config,ts.sys,nodepath.dirname(configPath))
//create program/compiler
const program = ts.createProgram({
rootNames:parsedConfig.fileNames,
options:parsedConfig.options
})
//emit all compiled files
const emitResult = program.emit()
//print emit errors/warnings (type errors)
const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics)
const formattedDiagnostics = ts.formatDiagnosticsWithColorAndContext(allDiagnostics, ts.createCompilerHost(parsedConfig.options))
console.log(formattedDiagnostics)
if (emitResult.emitSkipped || allDiagnostics.find((d) => d.category == ts.DiagnosticCategory.Error || d.category == ts.DiagnosticCategory.Warning)){
console.log("OT: Compilation Failed!")
process.exit(1)
}
}else console.log("OT: No Compilation Required...")
//save new compilation hash
saveNewCompilationHash()
}
//START BOT
console.log("OT: Compilation Succeeded!")
if (process.argv.includes("--compile-only")) process.exit(0) //exit when only compile is required!
console.log("OT: Starting Bot!")
require("./dist/src/index.js")
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["palestinian"], "translators":["palestinian"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Arabic", "language":"Arabic",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["HanumeshGupta"], "translators":["HanumeshGupta"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Bengali", "language":"Bengali",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["guillee3"], "translators":["guillee3"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Catalan", "language":"Catalan",
+318 -318
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["DJj123dj"], "translators":["DJj123dj"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Custom", "language":"Custom",
@@ -13,94 +13,94 @@
"typeWarning":"[WARNING]", "typeWarning":"[WARNING]",
"typeInfo":"[INFO]", "typeInfo":"[INFO]",
"headerConfigChecker":"CONFIG CHECKER", "headerConfigChecker":"CONFIG CHECKER",
"headerDescription":"check for errors in your config files!", "headerDescription":"Validating config files...",
"footerError":"the bot won't start until all {0}'s are fixed!", "footerError":"The bot will not start until all {0}'s are resolved.",
"footerWarning":"it's recommended to fix all {0}'s before starting!", "footerWarning":"The bot may behave unexpectedly until all {0}'s are resolved.",
"footerSupport":"SUPPORT: {0} - DOCS: {1}", "footerSupport":"SUPPORT: {0} - DOCS: {1}",
"compactInformation":"use {0} for more information!", "compactInformation":"Use {0} for a detailed config report.",
"dataPath":"path", "dataPath":"path",
"dataDocs":"docs", "dataDocs":"docs",
"dataMessages":"message" "dataMessages":"message"
}, },
"messages":{ "messages":{
"stringTooShort":"This string can't be shorter than {0} characters!", "stringTooShort":"Text must be at least {0} characters long",
"stringTooLong":"This string can't be longer than {0} characters!", "stringTooLong":"Text must be no longer than {0} characters",
"stringLengthInvalid":"This string needs to be {0} characters long!", "stringLengthInvalid":"Text must be exactly {0} characters long",
"stringStartsWith":"This string needs to start with {0}!", "stringStartsWith":"Text must start with {0}",
"stringEndsWith":"This string needs to end with {0}!", "stringEndsWith":"Text must end with {0}",
"stringContains":"This string needs to contain {0}!", "stringContains":"Text must contain {0}",
"stringChoices":"This string can only be one of the following values: {0}!", "stringChoices":"Text must be one of the following: {0}",
"stringRegex":"This string is invalid!", "stringRegex":"Text does not match the required format",
"stringInvertedContains":"This string is not allowed to contain {0}!", "stringInvertedContains":"Text must not contain {0}",
"stringLowercase":"This string must be written in lowercase only!", "stringLowercase":"Text must be entirely lowercase",
"stringUppercase":"This string must be written in uppercase only!", "stringUppercase":"Text must be entirely uppercase",
"stringSpecialCharacters":"This string is not allowed to contain any special characters! (a-z, 0-9 & space only)", "stringSpecialCharacters":"Text must only contain letters (a–z), numbers (0–9), and spaces",
"stringNoSpaces":"This string is not allowed to contain spaces!", "stringNoSpaces":"Text must not contain spaces",
"stringCapitalWord":"It's recommended that each word in this string starts with a capital letter!", "stringCapitalWord":"Each word in this value should start with a capital letter",
"stringCapitalSentence":"It looks like some sentences in this string don't start with a capital letter!", "stringCapitalSentence":"One or more sentences in this value do not start with a capital letter",
"stringPunctuation":"It looks like the sentence in this string doesn't end with a punctuation mark!", "stringPunctuation":"The sentence in this value does not end with a punctuation mark",
"numberTooShort":"This number can't be shorter than {0} characters!", "numberTooShort":"Number must be at least {0} digits long",
"numberTooLong":"This number can't be longer than {0} characters!", "numberTooLong":"Number must be no longer than {0} digits",
"numberLengthInvalid":"This number needs to be {0} characters long!", "numberLengthInvalid":"Number must be exactly {0} digits long",
"numberTooSmall":"This number needs to be at least {0}!", "numberTooSmall":"Number must be at least {0}",
"numberTooLarge":"This number needs to be at most {0}!", "numberTooLarge":"Number must be at most {0}",
"numberNotEqual":"This number needs to be {0}!", "numberNotEqual":"Number must be exactly {0}",
"numberStep":"This number needs to be a multiple of {0}!", "numberStep":"Number must be a multiple of {0}",
"numberStepOffset":"This number needs to be a multiple of {0} starting with {1}!", "numberStepOffset":"Number must be a multiple of {0}, starting from {1}",
"numberStartsWith":"This number needs to start with {0}!", "numberStartsWith":"Number must start with {0}",
"numberEndsWith":"This number needs to end with {0}!", "numberEndsWith":"Number must end with {0}",
"numberContains":"This number needs to contain {0}!", "numberContains":"Number must contain {0}",
"numberChoices":"This number can only be one of the following values: {0}!", "numberChoices":"Number must be one of the following: {0}",
"numberFloat":"This number can't be a decimal!", "numberFloat":"Number must be a whole number",
"numberNegative":"This number can't be negative!", "numberNegative":"Number must be a positive number",
"numberPositive":"This number can't be positive!", "numberPositive":"Number must be a negative number",
"numberZero":"This number can't be zero!", "numberZero":"Number must not be zero",
"numberNan":"This number can't be NaN (Not A Number)!", "numberNan":"Number must be a valid number",
"numberInvertedContains":"This number is not allowed to contain {0}!", "numberInvertedContains":"Number must not contain {0}",
"booleanTrue":"This boolean can't be true!", "booleanTrue":"Boolean must be false",
"booleanFalse":"This boolean can't be false!", "booleanFalse":"Boolean must be true",
"arrayEmptyDisabled":"This array isn't allowed to be empty!", "arrayEmptyDisabled":"List must not be empty",
"arrayEmptyRequired":"This array is required to be empty!", "arrayEmptyRequired":"List must be empty",
"arrayTooShort":"This array needs to have a length of at least {0}!", "arrayTooShort":"List must have at least {0} items",
"arrayTooLong":"This array needs to have a length of at most {0}!", "arrayTooLong":"List must have at most {0} items",
"arrayLengthInvalid":"This array needs to have a length of {0}!", "arrayLengthInvalid":"List must have exactly {0} items",
"arrayInvalidTypes":"This array can only contain the following types: {0}!", "arrayInvalidTypes":"List may only contain the following types: {0}",
"arrayDouble":"This array doesn't allow the same value twice!", "arrayDouble":"List must not contain duplicate values",
"discordInvalidId":"This is an invalid discord {0} id!", "discordInvalidId":"Invalid Discord {0} ID",
"discordInvalidIdOptions":"This is an invalid discord {0} id! You can also use one of these: {1}!", "discordInvalidIdOptions":"Invalid Discord {0} ID. Alternatively, use one of the following: {1}",
"discordInvalidToken":"This is an invalid discord token (syntactically)!", "discordInvalidToken":"Invalid Discord token",
"colorInvalid":"This is an invalid hex color!", "colorInvalid":"Invalid hex color",
"emojiTooShort":"This string needs to have at least {0} emoji's!", "emojiTooShort":"Value must contain at least {0} emoji",
"emojiTooLong":"This string needs to have at most {0} emoji's!", "emojiTooLong":"Value must contain at most {0} emoji",
"emojiCustom":"This emoji can't be a custom discord emoji!", "emojiCustom":"Custom Discord emojis are not allowed here",
"emojiInvalid":"This is an invalid emoji!", "emojiInvalid":"Invalid emoji",
"urlInvalid":"This url is invalid!", "urlInvalid":"Invalid URL",
"urlInvalidHttp":"This url can only use the https:// protocol!", "urlInvalidHttp":"URL must use the https:// protocol",
"urlInvalidProtocol":"This url can only use the http:// & https:// protocols!", "urlInvalidProtocol":"URL must use the http:// or https:// protocol",
"urlInvalidHostname":"This url has a disallowed hostname!", "urlInvalidHostname":"URL hostname is not allowed",
"urlInvalidExtension":"This url has an invalid extension! Choose between: {0}!", "urlInvalidExtension":"Invalid URL extension. Allowed extensions: {0}",
"urlInvalidPath":"This url has an invalid path!", "urlInvalidPath":"Invalid URL path",
"idNotUnique":"This id isn't unique, use another id instead!", "idNotUnique":"This ID is already in use. Please choose a unique ID",
"idNonExistent":"The id {0} doesn't exist!", "idNonExistent":"ID {0} does not exist",
"invalidType":"This property needs to be the type: {0}!", "invalidType":"Property must be of type: {0}",
"propertyMissing":"The property {0} is missing from this object!", "propertyMissing":"Required property {0} is missing from the object",
"propertyOptional":"The property {0} is optional in this object!", "propertyOptional":"Property {0} is optional in the object",
"objectDisabled":"This object is disabled, enable it using {0}!", "objectDisabled":"This object is disabled. Enable it using {0}",
"nullInvalid":"This property can't be null!", "nullInvalid":"Property must not be null",
"switchInvalidType":"This needs to be one of the following types: {0}!", "switchInvalidType":"Value must be one of the following types: {0}",
"objectSwitchInvalid":"This object needs to be one of the following types: {0}!", "objectSwitchInvalid":"Object must be one of the following types: {0}",
"invalidLanguage":"This is an invalid language!", "invalidLanguage":"Invalid language",
"invalidButton":"This button needs to have at least an {0} or {1}!", "invalidButton":"Button must have at least an {0} or {1}",
"unusedOption":"The option {0} isn't used anywhere!", "unusedOption":"Option {0} is not used anywhere",
"unusedQuestion":"The question {0} isn't used anywhere!", "unusedQuestion":"Question {0} is not used anywhere",
"dropdownOption":"A panel with dropdown enabled can only contain options of the 'ticket' type!", "dropdownOption":"Panels with dropdown enabled may only contain options of the 'ticket' type",
"customInvalidVersion":"The version specified in your config does not match! Make sure you have updated the config to the latest version!" "customInvalidVersion":"Config version mismatch. Make sure to update your config to the latest version"
} }
}, },
"actions":{ "actions":{
@@ -159,118 +159,118 @@
"transfer":"Ticket Transferred" "transfer":"Ticket Transferred"
}, },
"descriptions":{ "descriptions":{
"create":"Your ticket has been created. Click the button below to access it!", "create":"Your ticket is ready. Click the button below to view and continue.",
"close":"The ticket has been closed successfully!", "close":"The ticket has been closed.",
"delete":"The ticket has been deleted successfully!", "delete":"The ticket has been deleted.",
"reopen":"The ticket has been reopened successfully!", "reopen":"The ticket has been reopened.",
"claim":"The ticket has been claimed successfully!", "claim":"The ticket has been claimed.",
"unclaim":"The ticket has been unclaimed successfully!", "unclaim":"The ticket has been unclaimed.",
"pin":"The ticket has been pinned successfully!", "pin":"The ticket has been pinned.",
"unpin":"The ticket has been unpinned successfully!", "unpin":"The ticket has been unpinned.",
"rename":"The ticket has been renamed to {0} successfully!", "rename":"The ticket has been renamed to {0}.",
"move":"The ticket has been moved to {0} successfully!", "move":"The ticket has been moved to {0}.",
"add":"{0} has been added to the ticket successfully!", "add":"{0} has been added to the ticket.",
"remove":"{0} has been removed from the ticket successfully!", "remove":"{0} has been removed from the ticket.",
"helpExplanation":"`<name>` => required parameter\n`[name]` => optional parameter", "helpExplanation":"`<name>` => required parameter\n`[name]` => optional parameter",
"statsReset":"The bot stats have been reset successfully!", "statsReset":"The bot statistics have been reset.",
"statsError":"Unable to view ticket stats!\n{0} is not a ticket!", "statsError":"Unable to retrieve ticket statistics.\n{0} is not a valid ticket.",
"blacklistAdd":"{0} has been blacklisted successfully!", "blacklistAdd":"{0} has been blacklisted.",
"blacklistRemove":"{0} has been released successfully!", "blacklistRemove":"{0} has been released.",
"blacklistGetSuccess":"{0} is currently blacklisted!", "blacklistGetSuccess":"{0} is blacklisted!",
"blacklistGetEmpty":"{0} is currently not blacklisted!", "blacklistGetEmpty":"{0} is not blacklisted!",
"blacklistViewEmpty":"No-one has been blacklisted yet!", "blacklistViewEmpty":"No users have been blacklisted yet.",
"blacklistViewTip":"Use \"/blacklist add\" to blacklist a user!", "blacklistViewTip":"Use \"/blacklist add\" to add a user to the blacklist.",
"clearVerify":"Are you sure you want to delete multiple tickets?\nThis action can't be undone!", "clearVerify":"Are you sure you want to delete multiple tickets?\nThis action cannot be undone.",
"clearReady":"{0} tickets have been deleted successfully!", "clearReady":"{0} ticket(s) have been deleted.",
"rolesEmpty":"No roles have been updated!", "rolesEmpty":"No roles were modified.",
"autocloseLeave":"This ticket has been autoclosed because the creator left the server!", "autocloseLeave":"This ticket was automatically closed because its creator left the server.",
"autocloseTimeout":"This ticket has been autoclosed because it has been inactive for more than `{0}h`!", "autocloseTimeout":"This ticket was automatically closed due to inactivity exceeding `{0}h`.",
"autodeleteLeave":"This ticket has been autodeleted because the creator left the server!", "autodeleteLeave":"This ticket was automatically deleted because its creator left the server.",
"autodeleteTimeout":"This ticket has been autodeleted because it has been inactive for more than `{0} days`!", "autodeleteTimeout":"This ticket was automatically deleted due to inactivity exceeding `{0} days`.",
"autocloseEnabled":"Autoclose has been enabled in this ticket!\nIt will be closed when it is inactive for more than `{0}h`!", "autocloseEnabled":"Autoclose has been enabled for this ticket.\nIt will close after `{0}h` of inactivity.",
"autocloseDisabled":"Autoclose has been disabled in this ticket!\nIt won't be closed automatically anymore!", "autocloseDisabled":"Autoclose has been disabled for this ticket.\nThis ticket will no longer close automatically.",
"autodeleteEnabled":"Autodelete has been enabled in this ticket!\nIt will be deleted when it is inactive for more than `{0} days`!", "autodeleteEnabled":"Autodelete has been enabled for this ticket.\nIt will be deleted after `{0} days` of inactivity.",
"autodeleteDisabled":"Autodelete has been disabled in this ticket!\nIt won't be deleted automatically anymore!", "autodeleteDisabled":"Autodelete has been disabled for this ticket.\nThis ticket will no longer be deleted automatically.",
"ticketMessageLimit":"You can only create {0} ticket(s) at the same time!", "ticketMessageLimit":"You can only have {0} active ticket(s) at a time.",
"ticketMessageAutoclose":"This ticket will be autoclosed when inactive for {0}h!", "ticketMessageAutoclose":"This ticket will automatically close after `{0}h` of inactivity.",
"ticketMessageAutodelete":"This ticket will be autodeleted when inactive for {0} days!", "ticketMessageAutodelete":"This ticket will automatically be deleted after `{0} days` of inactivity.",
"panelReady":"The panel is available in the followup message!\nThis message can now be deleted!", "panelReady":"The panel has been sent in the follow-up message.\nYou may now delete this message.",
"topicSet":"The channel topic has been changed by {0} successfully!", "topicSet":"The channel topic has been changed by {0}.",
"prioritySet":"The ticket priority has been changed to {0} by {1} successfully!", "prioritySet":"The ticket priority has been changed to {0} by {1}.",
"priorityGet":"The current priority of this ticket is {0}.", "priorityGet":"The priority of this ticket is {0}.",
"transfer":"The ticket ownership has been transferred from {0} to {1} by {2} successfully!" "transfer":"The ticket ownership has been transferred from {0} to {1} by {2}."
}, },
"modal":{ "modal":{
"closePlaceholder":"Why did you close this ticket?", "closePlaceholder":"Why would you like to close this ticket?",
"deletePlaceholder":"Why did you delete this ticket?", "deletePlaceholder":"Why would you like to delete this ticket?",
"reopenPlaceholder":"Why did you reopen this ticket?", "reopenPlaceholder":"Why would you like to reopen this ticket?",
"claimPlaceholder":"Why did you claim this ticket?", "claimPlaceholder":"Why would you like to claim this ticket?",
"unclaimPlaceholder":"Why did you unclaim this ticket?", "unclaimPlaceholder":"Why would you like to unclaim this ticket?",
"pinPlaceholder":"Why did you pin this ticket?", "pinPlaceholder":"Why would you like to pin this ticket?",
"unpinPlaceholder":"Why did you unpin this ticket?" "unpinPlaceholder":"Why would you like to unpin this ticket?"
}, },
"logs":{ "logs":{
"createLog":"A new ticket got created by {0}!", "createLog":"A new ticket got created by {0}.",
"closeLog":"This ticket has been closed by {0}!", "closeLog":"This ticket has been closed by {0}.",
"closeDm":"Your ticket has been closed in our server!", "closeDm":"Your ticket has been closed.",
"deleteLog":"This ticket has been deleted by {0}!", "deleteLog":"This ticket has been deleted by {0}.",
"deleteDm":"Your ticket has been deleted in our server!", "deleteDm":"Your ticket has been deleted.",
"reopenLog":"This ticket has been reopened by {0}!", "reopenLog":"This ticket has been reopened by {0}.",
"reopenDm":"Your ticket has been reopened in our server!", "reopenDm":"Your ticket has been reopened.",
"claimLog":"This ticket has been claimed by {0}!", "claimLog":"This ticket has been claimed by {0}.",
"claimDm":"Your ticket has been claimed in our server!", "claimDm":"Your ticket has been claimed.",
"unclaimLog":"This ticket has been unclaimed by {0}!", "unclaimLog":"This ticket has been unclaimed by {0}.",
"unclaimDm":"Your ticket has been unclaimed in our server!", "unclaimDm":"Your ticket has been unclaimed.",
"pinLog":"This ticket has been pinned by {0}!", "pinLog":"This ticket has been pinned by {0}.",
"pinDm":"Your ticket has been pinned in our server!", "pinDm":"Your ticket has been pinned.",
"unpinLog":"This ticket has been unpinned by {0}!", "unpinLog":"This ticket has been unpinned by {0}.",
"unpinDm":"Your ticket has been unpinned in our server!", "unpinDm":"Your ticket has been unpinned.",
"renameLog":"This ticket has been renamed to {0} by {1}!", "renameLog":"This ticket has been renamed to {0} by {1}.",
"renameDm":"Your ticket has been renamed to {0} in our server!", "renameDm":"Your ticket has been renamed to {0}.",
"moveLog":"This ticket has been moved to {0} by {1}!", "moveLog":"This ticket has been moved to {0} by {1}.",
"moveDm":"Your ticket has been moved to {0} in our server!", "moveDm":"Your ticket has been moved to {0}.",
"addLog":"{0} has been added to this ticket by {1}!", "addLog":"{0} has been added to this ticket by {1}.",
"addDm":"{0} has been added to your ticket in our server!", "addDm":"{0} has been added to your ticket.",
"removeLog":"{0} has been removed from this ticket by {1}!", "removeLog":"{0} has been removed from this ticket by {1}.",
"removeDm":"{0} has been removed from your ticket in our server!", "removeDm":"{0} has been removed from your ticket.",
"blacklistAddLog":"{0} was blacklisted by {1}!", "blacklistAddLog":"{0} has been blacklisted by {1}.",
"blacklistRemoveLog":"{0} was removed from the blacklist by {1}!", "blacklistRemoveLog":"{0} has been removed from the blacklist by {1}.",
"blacklistAddDm":"You have been blacklisted in our server!\nFrom now on, you are unable to create a ticket!", "blacklistAddDm":"You have been blacklisted from this server.\nYou are no longer able to create tickets.",
"blacklistRemoveDm":"You have been removed from the blacklist in our server!\nNow you can create tickets again!", "blacklistRemoveDm":"You have been removed from the blacklist.\nYou can now create tickets again.",
"clearLog":"{0} tickets have been deleted by {1}!", "clearLog":"{0} ticket(s) have been deleted by {1}.",
"transferLog":"The ownership of this ticket has been transferred from {0} to {1} by {2}!", "transferLog":"Ticket ownership has been transferred from {0} to {1} by {2}.",
"transferDm":"The ownership of your ticket has been transferred from {0} to {1} in our server!", "transferDm":"Ownership of your ticket has been transferred from {0} to {1}.",
"prioritySetLog":"The priority of this ticket has been changed to {0} by {1}!", "prioritySetLog":"The priority of this ticket has been set to {0} by {1}.",
"prioritySetDm":"The priority of your ticket has been changed to {0} in our server!", "prioritySetDm":"The priority of your ticket has been set to {0}.",
"roleUpdateLog":"{0} has updated their roles!", "roleUpdateLog":"{0} has modified their roles.",
"roleUpdateDm":"Your roles in our server have been updated!" "roleUpdateDm":"Your roles have been modified."
} }
}, },
"transcripts":{ "transcripts":{
"success":{ "success":{
"visit":"Visit Transcript", "visit":"Visit Transcript",
"ready":"Transcript Created", "ready":"Transcript Created",
"textFileDescription":"This is the text transcript of a deleted ticket!", "textFileDescription":"This is a text transcript of a deleted ticket.",
"htmlProgress":"Please wait while this html transcript is getting processed...", "htmlProgress":"Please wait while the HTML transcript is being generated...",
"createdChannel":"A new {0} transcript has been created in the server!", "createdChannel":"A new {0} transcript has been created in the server.",
"createdCreator":"A new {0} transcript has been created for one of your tickets!", "createdCreator":"A new {0} transcript has been created for one of your tickets.",
"createdParticipant":"A new {0} transcript has been created in one of the tickets you participated in!", "createdParticipant":"A new {0} transcript has been created for a ticket you participated in.",
"createdActiveAdmin":"A new {0} transcript has been created in one of the tickets you participated as admin!", "createdActiveAdmin":"A new {0} transcript has been created for a ticket you participated in as an admin.",
"createdEveryAdmin":"A new {0} transcript has been created in one of the tickets you were admin in!", "createdEveryAdmin":"A new {0} transcript has been created for a ticket you managed as an admin.",
"createdOther":"A new {0} transcript has been created!" "createdOther":"A new {0} transcript has been created."
}, },
"errors":{ "errors":{
"retry":"Retry", "retry":"Retry",
"continue":"Delete Without Transcript", "continue":"Delete Without Transcript",
"backup":"Create Backup Transcript", "backup":"Create Backup Transcript",
"error":"Something went wrong while trying to create the transcript.\nWhat would you like to do?\n\nThis ticket won't be deleted until you click one of these buttons.", "error":"Something went wrong while creating the transcript.\nWhat would you like to do?\n\nThis ticket will not be deleted until you select one of the options below.",
"title":"Transcript Error" "title":"Transcript Error"
}, },
"text":{ "text":{
@@ -279,7 +279,7 @@
"fileTitle":"FILE", "fileTitle":"FILE",
"fieldsTitle":"FIELDS", "fieldsTitle":"FIELDS",
"reactionsTitle":"REACTIONS", "reactionsTitle":"REACTIONS",
"statsTitle":"STATS", "statsTitle":"STATISTICS",
"emptyContent":"<content is empty>", "emptyContent":"<content is empty>",
"noTitle":"<no-title>", "noTitle":"<no-title>",
"noDesc":"<no-description>" "noDesc":"<no-description>"
@@ -302,68 +302,68 @@
"permissionError":"Permission Error" "permissionError":"Permission Error"
}, },
"descriptions":{ "descriptions":{
"askForInfo":"Contact the owner of this bot for more info!", "askForInfo":"Please contact the bot owner for more information.",
"askForInfoResolve":"Contact the bot owner of this bot if this issue doesn't resolve after a few tries.", "askForInfoResolve":"If the issue persists after a few attempts, please contact the bot owner.",
"internalError":"Failed to respond to this {0} due to an internal error!", "internalError":"An internal error occurred while processing this {0}.",
"optionMissing":"A required parameter is missing in this command!", "optionMissing":"A required parameter is missing for this command.",
"optionInvalid":"A parameter in this command is invalid!", "optionInvalid":"One or more parameters provided for this command are invalid.",
"optionInvalidChoose":"Choose between", "optionInvalidChoose":"Please choose between",
"unknownCommand":"Try visiting the help menu for more info!", "unknownCommand":"Please use the help menu for more information.",
"noPermissions":"You are not allowed to use this {0}!", "noPermissions":"You are not permitted to use this {0}.",
"noPermissionsList":"Required Permissions: (one of them)", "noPermissionsList":"Required permissions (one of the following):",
"noPermissionsCooldown":"You are not allowed to use this {0} because you have a cooldown!", "noPermissionsCooldown":"You cannot use this {0} while on cooldown.",
"noPermissionsBlacklist":"You are not allowed to use this {0} because you have been blacklisted!", "noPermissionsBlacklist":"You cannot use this {0} because you are blacklisted.",
"noPermissionsLimitGlobal":"You are not allowed to create a ticket because the server reached the max tickets limit!", "noPermissionsLimitGlobal":"You cannot create a ticket because the server has reached its maximum ticket limit.",
"noPermissionsLimitGlobalUser":"You are not allowed to create a ticket because you reached the max tickets limit!", "noPermissionsLimitGlobalUser":"You cannot create a ticket because you have reached your maximum ticket limit.",
"noPermissionsLimitOption":"You are not allowed to create a ticket because the server reached the max tickets limit for this option!", "noPermissionsLimitOption":"You cannot create a ticket because the server has reached the maximum ticket limit for this option.",
"noPermissionsLimitOptionUser":"You are not allowed to create a ticket because you reached the max tickets limit for this option!", "noPermissionsLimitOptionUser":"You cannot create a ticket because you have reached the maximum ticket limit for this option.",
"unknownTicket":"Try this command again in a valid ticket!", "unknownTicket":"Please run this command inside a valid ticket channel.",
"deprecatedTicket":"The current channel is not a valid ticket! It might have been a ticket from an old Open Ticket version!", "deprecatedTicket":"This channel is not recognized as a valid ticket. It may have been created with an older version of the bot.",
"notInGuild":"This {0} doesn't work in DM! Please try it again in a server!", "notInGuild":"This {0} cannot be used in direct messages. Please use it in a server.",
"channelRename":"Due to discord ratelimits, it's currently impossible for the bot to rename the channel. The channel will automatically be renamed over 10 minutes if the bot isn't rebooted.", "channelRename":"Due to Discord rate limits, the channel could not be renamed immediately. It will be renamed automatically within 10 minutes if the bot remains online.",
"channelRenameSource":"The source of this error is: {0}", "channelRenameSource":"Error source: {0}",
"busy":"Unable to use this {0}!\nThe ticket is currently being processed by the bot.\n\nPlease try again in a few seconds!", "busy":"This {0} is currently unavailable.\nThe ticket is being processed by the bot.\n\nPlease try again in a few seconds.",
"closeBeforeMessage":"This ticket cannot be closed/deleted before a message has been sent by a user.", "closeBeforeMessage":"This ticket cannot be closed or deleted before a user has sent a message.",
"closeBeforeAdminMessage":"This ticket cannot be closed/deleted before a message has been sent by a ticket admin or support member.", "closeBeforeAdminMessage":"This ticket cannot be closed or deleted before a support member or admin has sent a message.",
"unableToCreateTicket":"You are unable to create a ticket." "unableToCreateTicket":"You are currently unable to create a ticket."
}, },
"optionInvalidReasons":{ "optionInvalidReasons":{
"stringRegex":"Value doesn't match pattern!", "stringRegex":"The value does not match the required pattern.",
"stringMinLength":"Value needs to be at least {0} characters!", "stringMinLength":"The value must be at least {0} characters long.",
"stringMaxLength":"Value needs to be at most {0} characters!", "stringMaxLength":"The value must be at most {0} characters long.",
"numberInvalid":"Invalid number!", "numberInvalid":"Invalid number provided.",
"numberMin":"Number needs to be at least {0}!", "numberMin":"The number must be at least {0}.",
"numberMax":"Number needs to be at most {0}!", "numberMax":"The number must be at most {0}.",
"numberDecimal":"Number is not allowed to be a decimal!", "numberDecimal":"Decimals are not allowed.",
"numberNegative":"Number is not allowed to be negative!", "numberNegative":"Negative numbers are not allowed.",
"numberPositive":"Number is not allowed to be positive!", "numberPositive":"Positive numbers are not allowed.",
"numberZero":"Number is not allowed to be zero!", "numberZero":"Zero is not allowed.",
"channelNotFound":"Unable to find channel!", "channelNotFound":"Channel not found.",
"userNotFound":"Unable to find user!", "userNotFound":"User not found.",
"roleNotFound":"Unable to find role!", "roleNotFound":"Role not found.",
"memberNotFound":"Unable to find user!", "memberNotFound":"Member not found.",
"mentionableNotFound":"Unable to find user or role!", "mentionableNotFound":"User or role not found.",
"channelType":"Invalid channel type!", "channelType":"Invalid channel type.",
"notInGuild":"This option requires you to be in a server!" "notInGuild":"This option can only be used in a server."
}, },
"permissions":{ "permissions":{
"developer":"You need to be the developer of the bot.", "developer":"This action is restricted to the bot developer.",
"owner":"You need to be the server owner.", "owner":"You must be the server owner to use this.",
"admin":"You need to be a server admin.", "admin":"You must have administrator permissions to use this.",
"moderator":"You need to be a moderator.", "moderator":"You must be a moderator to use this.",
"support":"You need to be in the support team.", "support":"You must be part of the support team to use this.",
"member":"You need to be a member.", "member":"You must be a server member to use this.",
"discord-administrator":"You need to have the `ADMINISTRATOR` permission." "discord-administrator":"You must have the `ADMINISTRATOR` permission."
}, },
"actionInvalid":{ "actionInvalid":{
"close":"Ticket is already closed!", "close":"This ticket is already closed.",
"reopen":"Ticket is not closed yet!", "reopen":"This ticket is not closed.",
"claim":"Ticket is already claimed!", "claim":"This ticket is already claimed.",
"unclaim":"Ticket is not claimed yet!", "unclaim":"This ticket is not claimed.",
"pin":"Ticket is already pinned!", "pin":"This ticket is already pinned.",
"unpin":"Ticket is not pinned yet!", "unpin":"This ticket is not pinned.",
"add":"This user is already able to access the ticket!", "add":"This user already has access to this ticket.",
"remove":"Unable to remove this user from the ticket!" "remove":"This user does not have access to this ticket."
} }
}, },
"params":{ "params":{
@@ -432,107 +432,107 @@
} }
}, },
"commands":{ "commands":{
"reason":"Specify an optional reason that will be visible in logs.", "reason":"Optional reason shown in logs.",
"help":"Get a list of all the available commands.", "help":"Display all available commands.",
"panel":"Spawn a message with a dropdown or buttons (for ticket creation).", "panel":"Create a ticket panel (buttons or dropdown).",
"panelId":"The identifier of the panel that you want to spawn.", "panelId":"ID of the panel to spawn.",
"panelAutoUpdate":"Do you want this panel to automatically update when edited?", "panelAutoUpdate":"Automatically update this panel when edited.",
"ticket":"Instantly create a ticket.", "ticket":"Create a ticket instantly.",
"ticketId":"The identifier of the ticket that you want to create.", "ticketId":"ID of the ticket to create.",
"close":"Close a ticket.", "close":"Close this ticket.",
"delete":"Delete a ticket.", "delete":"Delete this ticket.",
"deleteNoTranscript":"Delete this ticket without creating a transcript.", "deleteNoTranscript":"Delete ticket without saving a transcript.",
"reopen":"Reopen a ticket.", "reopen":"Reopen a closed ticket.",
"claim":"Claim a ticket.", "claim":"Claim this ticket.",
"claimUser":"Claim this ticket to someone else instead of yourself.", "claimUser":"Claim the ticket for another user.",
"unclaim":"Unclaim a ticket.", "unclaim":"Unclaim this ticket.",
"pin":"Pin a ticket.", "pin":"Pin this ticket.",
"unpin":"Unpin a ticket.", "unpin":"Unpin this ticket.",
"move":"Move a ticket.", "move":"Move ticket to another option.",
"moveId":"The identifier of the option that you want to move to.", "moveId":"Target option ID.",
"rename":"Rename a ticket.", "rename":"Rename this ticket.",
"renameName":"The new name for this ticket.", "renameName":"New name for the ticket.",
"add":"Add a user to a ticket.", "add":"Add a user to this ticket.",
"addUser":"The user to add.", "addUser":"User to add.",
"remove":"Remove a user from a ticket.", "remove":"Remove a user from this ticket.",
"removeUser":"The user to remove.", "removeUser":"User to remove.",
"blacklist":"Manage the ticket blacklist.", "blacklist":"Manage the blacklist.",
"blacklistView":"View a list of the current blacklist.", "blacklistView":"View all blacklisted users.",
"blacklistAdd":"Add a user to the blacklist.", "blacklistAdd":"Add a user to the blacklist.",
"blacklistRemove":"Remove a user from the blacklist.", "blacklistRemove":"Remove a user from the blacklist.",
"blacklistGet":"Get the details from a blacklisted user.", "blacklistGet":"View blacklist entry details.",
"blacklistGetUser":"The user to get details from.", "blacklistGetUser":"User to look up.",
"stats":"View statistics from the bot, a member or a ticket.", "stats":"View bot, user or ticket statistics.",
"statsReset":"Reset all the stats of the bot (and start counting from zero).", "statsReset":"Reset all bot statistics.",
"statsGlobal":"View the global stats.", "statsGlobal":"View global bot statistics.",
"statsUser":"View the stats from a user in the server.", "statsUser":"View a user's statistics.",
"statsUserUser":"The user to view.", "statsUserUser":"User to view.",
"statsTicket":"View the stats of a ticket in the server.", "statsTicket":"View ticket statistics.",
"statsTicketTicket":"The ticket to view.", "statsTicketTicket":"Ticket to view.",
"clear":"Delete multiple tickets at the same time.", "clear":"Delete multiple tickets at once.",
"clearFilter":"The filter for clearing tickets.", "clearFilter":"Filter used when clearing tickets.",
"clearFilters":{ "clearFilters":{
"all":"All", "all":"All tickets",
"open":"Open", "open":"Open tickets",
"close":"Closed", "close":"Closed tickets",
"claim":"Claimed", "claim":"Claimed tickets",
"unclaim":"Unclaimed", "unclaim":"Unclaimed tickets",
"pin":"Pinned", "pin":"Pinned tickets",
"unpin":"Unpinned", "unpin":"Unpinned tickets",
"autoclose":"Autoclosed" "autoclose":"Autoclosed tickets"
}, },
"autoclose":"Manage autoclose in a ticket.", "autoclose":"Manage ticket autoclose.",
"autocloseDisable":"Disable autoclose in this ticket.", "autocloseDisable":"Disable autoclose.",
"autocloseEnable":"Enable autoclose in this ticket.", "autocloseEnable":"Enable autoclose.",
"autocloseEnableTime":"The amount of hours this ticket needs to be inactive to close it.", "autocloseEnableTime":"Hours of inactivity before closing.",
"autodelete":"Manage autodelete in a ticket.", "autodelete":"Manage ticket autodelete.",
"autodeleteDisable":"Disable autodelete in this ticket.", "autodeleteDisable":"Disable autodelete.",
"autodeleteEnable":"Enable autodelete in this ticket.", "autodeleteEnable":"Enable autodelete.",
"autodeleteEnableTime":"The amount of days this ticket needs to be inactive to delete it.", "autodeleteEnableTime":"Days of inactivity before deletion.",
"topic":"Manage the topic of the ticket channel.", "topic":"Manage ticket channel topic.",
"topicSet":"Set the topic of the ticket channel.", "topicSet":"Set the ticket channel topic.",
"topicValue":"The new topic of the channel.", "topicValue":"New channel topic text.",
"topicList":"Get a list of all tickets with their topic and stats.", "topicList":"List all ticket channel topics.",
"priority":"Manage the priority of the ticket.", "priority":"Manage ticket priority.",
"prioritySet":"Set the priority of the ticket.", "prioritySet":"Set ticket priority.",
"priorityValue":"The priority of the channel.", "priorityValue":"Priority level.",
"priorityGet":"Get the priority of the ticket.", "priorityGet":"View ticket priority.",
"priorityList":"Get a list of all tickets with their priority status.", "priorityList":"List all ticket priorities.",
"transfer":"Transfer the ticket ownership from one user to another.", "transfer":"Transfer ticket ownership.",
"transferUser":"The user to transfer to." "transferUser":"User to transfer to."
}, },
"helpMenu":{ "helpMenu":{
"help":"Get a list of all the available commands.", "help":"View all available commands.",
"ticket":"Instantly create a ticket.", "ticket":"Create a ticket instantly.",
"close":"Close a ticket, this disables writing in this channel.", "close":"Close this ticket and disable messaging in the channel.",
"delete":"Delete a ticket, this creates a transcript when enabled.", "delete":"Delete this ticket (creates a transcript if enabled).",
"reopen":"Reopen a ticket, this enables writing in this channel again.", "reopen":"Reopen a closed ticket and restore messaging.",
"pin":"Pin a ticket. This will move the ticket to the top and will add a '📌' emoij to the name.", "pin":"Pin this ticket and move it to the top with '📌'.",
"unpin":"Unpin a ticket. The ticket will stay on it's position but will lose the '📌' emoij.", "unpin":"Unpin this ticket and remove the '📌' emoji.",
"move":"Move a ticket. This will change the type of this ticket.", "move":"Move this ticket to a different option or ticket type.",
"rename":"Rename a ticket. This will change the channel name of this ticket.", "rename":"Rename this ticket channel.",
"claim":"Claim a ticket. With this, you can let your team know you are handling this ticket.", "claim":"Claim this ticket to show you are handling it.",
"unclaim":"Unclaim a ticket. With this, you can let your team know that this ticket is free again.", "unclaim":"Unclaim this ticket to mark it as available.",
"add":"Add a user to a ticket. This will allow the user to read & write in this ticket.", "add":"Add a user to this ticket.",
"remove":"Remove a user from a ticket. This will remove the ability to read & write for a user in this ticket.", "remove":"Remove a user's access from this ticket.",
"panel":"Spawn a message with a dropdown or buttons (for ticket creation).", "panel":"Create a ticket panel with buttons or a dropdown.",
"blacklistView":"View a list of the current blacklist.", "blacklistView":"View all blacklisted users.",
"blacklistAdd":"Add a user to the blacklist.", "blacklistAdd":"Add a user to the blacklist.",
"blacklistRemove":"Remove a user from the blacklist.", "blacklistRemove":"Remove a user from the blacklist.",
"blacklistGet":"Get the details from a blacklisted user.", "blacklistGet":"View details of a blacklisted user.",
"statsGlobal":"View the global stats.", "statsGlobal":"View global bot statistics.",
"statsTicket":"View the stats of a ticket in the server.", "statsTicket":"View statistics for a ticket.",
"statsUser":"View the stats from a user in the server.", "statsUser":"View statistics for a user.",
"statsReset":"Reset all the stats of the bot (and start counting from zero).", "statsReset":"Reset all bot statistics.",
"autocloseDisable":"Disable autoclose in this ticket.", "autocloseDisable":"Disable autoclose for this ticket.",
"autocloseEnable":"Enable autoclose in this ticket.", "autocloseEnable":"Enable autoclose for this ticket.",
"autodeleteDisable":"Disable autodelete in this ticket.", "autodeleteDisable":"Disable autodelete for this ticket.",
"autodeleteEnable":"Enable autodelete in this ticket.", "autodeleteEnable":"Enable autodelete for this ticket.",
"categories":{ "categories":{
"general":"General Commands", "general":"General Commands",
"basicTicket":"Basic Ticket Commands", "basicTicket":"Basic Ticket Commands",
@@ -545,10 +545,10 @@
}, },
"stats":{ "stats":{
"scopes":{ "scopes":{
"global":"Global Stats", "global":"Global Statistics",
"system":"System Stats", "system":"System Statistics",
"user":"User Stats", "user":"User Statistics",
"ticket":"Ticket Stats", "ticket":"Ticket Statistics",
"participants":"Participants", "participants":"Participants",
"messages":"Messages" "messages":"Messages"
}, },
@@ -592,9 +592,9 @@
} }
}, },
"panel":{ "panel":{
"selectTicket":"Select your ticket", "selectTicket":"Select a ticket",
"selectRole":"Select your role", "selectRole":"Select a role",
"selectOption":"Select your option" "selectOption":"Select an option"
}, },
"priorities":{ "priorities":{
"urgent":"Urgent", "urgent":"Urgent",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["spyeye_"], "translators":["spyeye_"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Czech", "language":"Czech",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["the_gamer"], "translators":["the_gamer"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Danish", "language":"Danish",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["DJj123dj"], "translators":["DJj123dj"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Dutch", "language":"Dutch",
+318 -318
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["DJj123dj"], "translators":["DJj123dj"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"English", "language":"English",
@@ -13,94 +13,94 @@
"typeWarning":"[WARNING]", "typeWarning":"[WARNING]",
"typeInfo":"[INFO]", "typeInfo":"[INFO]",
"headerConfigChecker":"CONFIG CHECKER", "headerConfigChecker":"CONFIG CHECKER",
"headerDescription":"check for errors in your config files!", "headerDescription":"Validating config files...",
"footerError":"the bot won't start until all {0}'s are fixed!", "footerError":"The bot will not start until all {0}'s are resolved.",
"footerWarning":"it's recommended to fix all {0}'s before starting!", "footerWarning":"The bot may behave unexpectedly until all {0}'s are resolved.",
"footerSupport":"SUPPORT: {0} - DOCS: {1}", "footerSupport":"SUPPORT: {0} - DOCS: {1}",
"compactInformation":"use {0} for more information!", "compactInformation":"Use {0} for a detailed config report.",
"dataPath":"path", "dataPath":"path",
"dataDocs":"docs", "dataDocs":"docs",
"dataMessages":"message" "dataMessages":"message"
}, },
"messages":{ "messages":{
"stringTooShort":"This string can't be shorter than {0} characters!", "stringTooShort":"Text must be at least {0} characters long",
"stringTooLong":"This string can't be longer than {0} characters!", "stringTooLong":"Text must be no longer than {0} characters",
"stringLengthInvalid":"This string needs to be {0} characters long!", "stringLengthInvalid":"Text must be exactly {0} characters long",
"stringStartsWith":"This string needs to start with {0}!", "stringStartsWith":"Text must start with {0}",
"stringEndsWith":"This string needs to end with {0}!", "stringEndsWith":"Text must end with {0}",
"stringContains":"This string needs to contain {0}!", "stringContains":"Text must contain {0}",
"stringChoices":"This string can only be one of the following values: {0}!", "stringChoices":"Text must be one of the following: {0}",
"stringRegex":"This string is invalid!", "stringRegex":"Text does not match the required format",
"stringInvertedContains":"This string is not allowed to contain {0}!", "stringInvertedContains":"Text must not contain {0}",
"stringLowercase":"This string must be written in lowercase only!", "stringLowercase":"Text must be entirely lowercase",
"stringUppercase":"This string must be written in uppercase only!", "stringUppercase":"Text must be entirely uppercase",
"stringSpecialCharacters":"This string is not allowed to contain any special characters! (a-z, 0-9 & space only)", "stringSpecialCharacters":"Text must only contain letters (a–z), numbers (0–9), and spaces",
"stringNoSpaces":"This string is not allowed to contain spaces!", "stringNoSpaces":"Text must not contain spaces",
"stringCapitalWord":"It's recommended that each word in this string starts with a capital letter!", "stringCapitalWord":"Each word in this value should start with a capital letter",
"stringCapitalSentence":"It looks like some sentences in this string don't start with a capital letter!", "stringCapitalSentence":"One or more sentences in this value do not start with a capital letter",
"stringPunctuation":"It looks like the sentence in this string doesn't end with a punctuation mark!", "stringPunctuation":"The sentence in this value does not end with a punctuation mark",
"numberTooShort":"This number can't be shorter than {0} characters!", "numberTooShort":"Number must be at least {0} digits long",
"numberTooLong":"This number can't be longer than {0} characters!", "numberTooLong":"Number must be no longer than {0} digits",
"numberLengthInvalid":"This number needs to be {0} characters long!", "numberLengthInvalid":"Number must be exactly {0} digits long",
"numberTooSmall":"This number needs to be at least {0}!", "numberTooSmall":"Number must be at least {0}",
"numberTooLarge":"This number needs to be at most {0}!", "numberTooLarge":"Number must be at most {0}",
"numberNotEqual":"This number needs to be {0}!", "numberNotEqual":"Number must be exactly {0}",
"numberStep":"This number needs to be a multiple of {0}!", "numberStep":"Number must be a multiple of {0}",
"numberStepOffset":"This number needs to be a multiple of {0} starting with {1}!", "numberStepOffset":"Number must be a multiple of {0}, starting from {1}",
"numberStartsWith":"This number needs to start with {0}!", "numberStartsWith":"Number must start with {0}",
"numberEndsWith":"This number needs to end with {0}!", "numberEndsWith":"Number must end with {0}",
"numberContains":"This number needs to contain {0}!", "numberContains":"Number must contain {0}",
"numberChoices":"This number can only be one of the following values: {0}!", "numberChoices":"Number must be one of the following: {0}",
"numberFloat":"This number can't be a decimal!", "numberFloat":"Number must be a whole number",
"numberNegative":"This number can't be negative!", "numberNegative":"Number must be a positive number",
"numberPositive":"This number can't be positive!", "numberPositive":"Number must be a negative number",
"numberZero":"This number can't be zero!", "numberZero":"Number must not be zero",
"numberNan":"This number can't be NaN (Not A Number)!", "numberNan":"Number must be a valid number",
"numberInvertedContains":"This number is not allowed to contain {0}!", "numberInvertedContains":"Number must not contain {0}",
"booleanTrue":"This boolean can't be true!", "booleanTrue":"Boolean must be false",
"booleanFalse":"This boolean can't be false!", "booleanFalse":"Boolean must be true",
"arrayEmptyDisabled":"This array isn't allowed to be empty!", "arrayEmptyDisabled":"List must not be empty",
"arrayEmptyRequired":"This array is required to be empty!", "arrayEmptyRequired":"List must be empty",
"arrayTooShort":"This array needs to have a length of at least {0}!", "arrayTooShort":"List must have at least {0} items",
"arrayTooLong":"This array needs to have a length of at most {0}!", "arrayTooLong":"List must have at most {0} items",
"arrayLengthInvalid":"This array needs to have a length of {0}!", "arrayLengthInvalid":"List must have exactly {0} items",
"arrayInvalidTypes":"This array can only contain the following types: {0}!", "arrayInvalidTypes":"List may only contain the following types: {0}",
"arrayDouble":"This array doesn't allow the same value twice!", "arrayDouble":"List must not contain duplicate values",
"discordInvalidId":"This is an invalid discord {0} id!", "discordInvalidId":"Invalid Discord {0} ID",
"discordInvalidIdOptions":"This is an invalid discord {0} id! You can also use one of these: {1}!", "discordInvalidIdOptions":"Invalid Discord {0} ID. Alternatively, use one of the following: {1}",
"discordInvalidToken":"This is an invalid discord token (syntactically)!", "discordInvalidToken":"Invalid Discord token",
"colorInvalid":"This is an invalid hex color!", "colorInvalid":"Invalid hex color",
"emojiTooShort":"This string needs to have at least {0} emoji's!", "emojiTooShort":"Value must contain at least {0} emoji",
"emojiTooLong":"This string needs to have at most {0} emoji's!", "emojiTooLong":"Value must contain at most {0} emoji",
"emojiCustom":"This emoji can't be a custom discord emoji!", "emojiCustom":"Custom Discord emojis are not allowed here",
"emojiInvalid":"This is an invalid emoji!", "emojiInvalid":"Invalid emoji",
"urlInvalid":"This url is invalid!", "urlInvalid":"Invalid URL",
"urlInvalidHttp":"This url can only use the https:// protocol!", "urlInvalidHttp":"URL must use the https:// protocol",
"urlInvalidProtocol":"This url can only use the http:// & https:// protocols!", "urlInvalidProtocol":"URL must use the http:// or https:// protocol",
"urlInvalidHostname":"This url has a disallowed hostname!", "urlInvalidHostname":"URL hostname is not allowed",
"urlInvalidExtension":"This url has an invalid extension! Choose between: {0}!", "urlInvalidExtension":"Invalid URL extension. Allowed extensions: {0}",
"urlInvalidPath":"This url has an invalid path!", "urlInvalidPath":"Invalid URL path",
"idNotUnique":"This id isn't unique, use another id instead!", "idNotUnique":"This ID is already in use. Please choose a unique ID",
"idNonExistent":"The id {0} doesn't exist!", "idNonExistent":"ID {0} does not exist",
"invalidType":"This property needs to be the type: {0}!", "invalidType":"Property must be of type: {0}",
"propertyMissing":"The property {0} is missing from this object!", "propertyMissing":"Required property {0} is missing from the object",
"propertyOptional":"The property {0} is optional in this object!", "propertyOptional":"Property {0} is optional in the object",
"objectDisabled":"This object is disabled, enable it using {0}!", "objectDisabled":"This object is disabled. Enable it using {0}",
"nullInvalid":"This property can't be null!", "nullInvalid":"Property must not be null",
"switchInvalidType":"This needs to be one of the following types: {0}!", "switchInvalidType":"Value must be one of the following types: {0}",
"objectSwitchInvalid":"This object needs to be one of the following types: {0}!", "objectSwitchInvalid":"Object must be one of the following types: {0}",
"invalidLanguage":"This is an invalid language!", "invalidLanguage":"Invalid language",
"invalidButton":"This button needs to have at least an {0} or {1}!", "invalidButton":"Button must have at least an {0} or {1}",
"unusedOption":"The option {0} isn't used anywhere!", "unusedOption":"Option {0} is not used anywhere",
"unusedQuestion":"The question {0} isn't used anywhere!", "unusedQuestion":"Question {0} is not used anywhere",
"dropdownOption":"A panel with dropdown enabled can only contain options of the 'ticket' type!", "dropdownOption":"Panels with dropdown enabled may only contain options of the 'ticket' type",
"customInvalidVersion":"The version specified in your config does not match! Make sure you have updated the config to the latest version!" "customInvalidVersion":"Config version mismatch. Make sure to update your config to the latest version"
} }
}, },
"actions":{ "actions":{
@@ -159,118 +159,118 @@
"transfer":"Ticket Transferred" "transfer":"Ticket Transferred"
}, },
"descriptions":{ "descriptions":{
"create":"Your ticket has been created. Click the button below to access it!", "create":"Your ticket is ready. Click the button below to view and continue.",
"close":"The ticket has been closed successfully!", "close":"The ticket has been closed.",
"delete":"The ticket has been deleted successfully!", "delete":"The ticket has been deleted.",
"reopen":"The ticket has been reopened successfully!", "reopen":"The ticket has been reopened.",
"claim":"The ticket has been claimed successfully!", "claim":"The ticket has been claimed.",
"unclaim":"The ticket has been unclaimed successfully!", "unclaim":"The ticket has been unclaimed.",
"pin":"The ticket has been pinned successfully!", "pin":"The ticket has been pinned.",
"unpin":"The ticket has been unpinned successfully!", "unpin":"The ticket has been unpinned.",
"rename":"The ticket has been renamed to {0} successfully!", "rename":"The ticket has been renamed to {0}.",
"move":"The ticket has been moved to {0} successfully!", "move":"The ticket has been moved to {0}.",
"add":"{0} has been added to the ticket successfully!", "add":"{0} has been added to the ticket.",
"remove":"{0} has been removed from the ticket successfully!", "remove":"{0} has been removed from the ticket.",
"helpExplanation":"`<name>` => required parameter\n`[name]` => optional parameter", "helpExplanation":"`<name>` => required parameter\n`[name]` => optional parameter",
"statsReset":"The bot stats have been reset successfully!", "statsReset":"The bot statistics have been reset.",
"statsError":"Unable to view ticket stats!\n{0} is not a ticket!", "statsError":"Unable to retrieve ticket statistics.\n{0} is not a valid ticket.",
"blacklistAdd":"{0} has been blacklisted successfully!", "blacklistAdd":"{0} has been blacklisted.",
"blacklistRemove":"{0} has been released successfully!", "blacklistRemove":"{0} has been released.",
"blacklistGetSuccess":"{0} is currently blacklisted!", "blacklistGetSuccess":"{0} is blacklisted!",
"blacklistGetEmpty":"{0} is currently not blacklisted!", "blacklistGetEmpty":"{0} is not blacklisted!",
"blacklistViewEmpty":"No-one has been blacklisted yet!", "blacklistViewEmpty":"No users have been blacklisted yet.",
"blacklistViewTip":"Use \"/blacklist add\" to blacklist a user!", "blacklistViewTip":"Use \"/blacklist add\" to add a user to the blacklist.",
"clearVerify":"Are you sure you want to delete multiple tickets?\nThis action can't be undone!", "clearVerify":"Are you sure you want to delete multiple tickets?\nThis action cannot be undone.",
"clearReady":"{0} tickets have been deleted successfully!", "clearReady":"{0} ticket(s) have been deleted.",
"rolesEmpty":"No roles have been updated!", "rolesEmpty":"No roles were modified.",
"autocloseLeave":"This ticket has been autoclosed because the creator left the server!", "autocloseLeave":"This ticket was automatically closed because its creator left the server.",
"autocloseTimeout":"This ticket has been autoclosed because it has been inactive for more than `{0}h`!", "autocloseTimeout":"This ticket was automatically closed due to inactivity exceeding `{0}h`.",
"autodeleteLeave":"This ticket has been autodeleted because the creator left the server!", "autodeleteLeave":"This ticket was automatically deleted because its creator left the server.",
"autodeleteTimeout":"This ticket has been autodeleted because it has been inactive for more than `{0} days`!", "autodeleteTimeout":"This ticket was automatically deleted due to inactivity exceeding `{0} days`.",
"autocloseEnabled":"Autoclose has been enabled in this ticket!\nIt will be closed when it is inactive for more than `{0}h`!", "autocloseEnabled":"Autoclose has been enabled for this ticket.\nIt will close after `{0}h` of inactivity.",
"autocloseDisabled":"Autoclose has been disabled in this ticket!\nIt won't be closed automatically anymore!", "autocloseDisabled":"Autoclose has been disabled for this ticket.\nThis ticket will no longer close automatically.",
"autodeleteEnabled":"Autodelete has been enabled in this ticket!\nIt will be deleted when it is inactive for more than `{0} days`!", "autodeleteEnabled":"Autodelete has been enabled for this ticket.\nIt will be deleted after `{0} days` of inactivity.",
"autodeleteDisabled":"Autodelete has been disabled in this ticket!\nIt won't be deleted automatically anymore!", "autodeleteDisabled":"Autodelete has been disabled for this ticket.\nThis ticket will no longer be deleted automatically.",
"ticketMessageLimit":"You can only create {0} ticket(s) at the same time!", "ticketMessageLimit":"You can only have {0} active ticket(s) at a time.",
"ticketMessageAutoclose":"This ticket will be autoclosed when inactive for {0}h!", "ticketMessageAutoclose":"This ticket will automatically close after `{0}h` of inactivity.",
"ticketMessageAutodelete":"This ticket will be autodeleted when inactive for {0} days!", "ticketMessageAutodelete":"This ticket will automatically be deleted after `{0} days` of inactivity.",
"panelReady":"The panel is available in the followup message!\nThis message can now be deleted!", "panelReady":"The panel has been sent in the follow-up message.\nYou may now delete this message.",
"topicSet":"The channel topic has been changed by {0} successfully!", "topicSet":"The channel topic has been changed by {0}.",
"prioritySet":"The ticket priority has been changed to {0} by {1} successfully!", "prioritySet":"The ticket priority has been changed to {0} by {1}.",
"priorityGet":"The current priority of this ticket is {0}.", "priorityGet":"The priority of this ticket is {0}.",
"transfer":"The ticket ownership has been transferred from {0} to {1} by {2} successfully!" "transfer":"The ticket ownership has been transferred from {0} to {1} by {2}."
}, },
"modal":{ "modal":{
"closePlaceholder":"Why did you close this ticket?", "closePlaceholder":"Why would you like to close this ticket?",
"deletePlaceholder":"Why did you delete this ticket?", "deletePlaceholder":"Why would you like to delete this ticket?",
"reopenPlaceholder":"Why did you reopen this ticket?", "reopenPlaceholder":"Why would you like to reopen this ticket?",
"claimPlaceholder":"Why did you claim this ticket?", "claimPlaceholder":"Why would you like to claim this ticket?",
"unclaimPlaceholder":"Why did you unclaim this ticket?", "unclaimPlaceholder":"Why would you like to unclaim this ticket?",
"pinPlaceholder":"Why did you pin this ticket?", "pinPlaceholder":"Why would you like to pin this ticket?",
"unpinPlaceholder":"Why did you unpin this ticket?" "unpinPlaceholder":"Why would you like to unpin this ticket?"
}, },
"logs":{ "logs":{
"createLog":"A new ticket got created by {0}!", "createLog":"A new ticket got created by {0}.",
"closeLog":"This ticket has been closed by {0}!", "closeLog":"This ticket has been closed by {0}.",
"closeDm":"Your ticket has been closed in our server!", "closeDm":"Your ticket has been closed.",
"deleteLog":"This ticket has been deleted by {0}!", "deleteLog":"This ticket has been deleted by {0}.",
"deleteDm":"Your ticket has been deleted in our server!", "deleteDm":"Your ticket has been deleted.",
"reopenLog":"This ticket has been reopened by {0}!", "reopenLog":"This ticket has been reopened by {0}.",
"reopenDm":"Your ticket has been reopened in our server!", "reopenDm":"Your ticket has been reopened.",
"claimLog":"This ticket has been claimed by {0}!", "claimLog":"This ticket has been claimed by {0}.",
"claimDm":"Your ticket has been claimed in our server!", "claimDm":"Your ticket has been claimed.",
"unclaimLog":"This ticket has been unclaimed by {0}!", "unclaimLog":"This ticket has been unclaimed by {0}.",
"unclaimDm":"Your ticket has been unclaimed in our server!", "unclaimDm":"Your ticket has been unclaimed.",
"pinLog":"This ticket has been pinned by {0}!", "pinLog":"This ticket has been pinned by {0}.",
"pinDm":"Your ticket has been pinned in our server!", "pinDm":"Your ticket has been pinned.",
"unpinLog":"This ticket has been unpinned by {0}!", "unpinLog":"This ticket has been unpinned by {0}.",
"unpinDm":"Your ticket has been unpinned in our server!", "unpinDm":"Your ticket has been unpinned.",
"renameLog":"This ticket has been renamed to {0} by {1}!", "renameLog":"This ticket has been renamed to {0} by {1}.",
"renameDm":"Your ticket has been renamed to {0} in our server!", "renameDm":"Your ticket has been renamed to {0}.",
"moveLog":"This ticket has been moved to {0} by {1}!", "moveLog":"This ticket has been moved to {0} by {1}.",
"moveDm":"Your ticket has been moved to {0} in our server!", "moveDm":"Your ticket has been moved to {0}.",
"addLog":"{0} has been added to this ticket by {1}!", "addLog":"{0} has been added to this ticket by {1}.",
"addDm":"{0} has been added to your ticket in our server!", "addDm":"{0} has been added to your ticket.",
"removeLog":"{0} has been removed from this ticket by {1}!", "removeLog":"{0} has been removed from this ticket by {1}.",
"removeDm":"{0} has been removed from your ticket in our server!", "removeDm":"{0} has been removed from your ticket.",
"blacklistAddLog":"{0} was blacklisted by {1}!", "blacklistAddLog":"{0} has been blacklisted by {1}.",
"blacklistRemoveLog":"{0} was removed from the blacklist by {1}!", "blacklistRemoveLog":"{0} has been removed from the blacklist by {1}.",
"blacklistAddDm":"You have been blacklisted in our server!\nFrom now on, you are unable to create a ticket!", "blacklistAddDm":"You have been blacklisted from this server.\nYou are no longer able to create tickets.",
"blacklistRemoveDm":"You have been removed from the blacklist in our server!\nNow you can create tickets again!", "blacklistRemoveDm":"You have been removed from the blacklist.\nYou can now create tickets again.",
"clearLog":"{0} tickets have been deleted by {1}!", "clearLog":"{0} ticket(s) have been deleted by {1}.",
"transferLog":"The ownership of this ticket has been transferred from {0} to {1} by {2}!", "transferLog":"Ticket ownership has been transferred from {0} to {1} by {2}.",
"transferDm":"The ownership of your ticket has been transferred from {0} to {1} in our server!", "transferDm":"Ownership of your ticket has been transferred from {0} to {1}.",
"prioritySetLog":"The priority of this ticket has been changed to {0} by {1}!", "prioritySetLog":"The priority of this ticket has been set to {0} by {1}.",
"prioritySetDm":"The priority of your ticket has been changed to {0} in our server!", "prioritySetDm":"The priority of your ticket has been set to {0}.",
"roleUpdateLog":"{0} has updated their roles!", "roleUpdateLog":"{0} has modified their roles.",
"roleUpdateDm":"Your roles in our server have been updated!" "roleUpdateDm":"Your roles have been modified."
} }
}, },
"transcripts":{ "transcripts":{
"success":{ "success":{
"visit":"Visit Transcript", "visit":"Visit Transcript",
"ready":"Transcript Created", "ready":"Transcript Created",
"textFileDescription":"This is the text transcript of a deleted ticket!", "textFileDescription":"This is a text transcript of a deleted ticket.",
"htmlProgress":"Please wait while this html transcript is getting processed...", "htmlProgress":"Please wait while the HTML transcript is being generated...",
"createdChannel":"A new {0} transcript has been created in the server!", "createdChannel":"A new {0} transcript has been created in the server.",
"createdCreator":"A new {0} transcript has been created for one of your tickets!", "createdCreator":"A new {0} transcript has been created for one of your tickets.",
"createdParticipant":"A new {0} transcript has been created in one of the tickets you participated in!", "createdParticipant":"A new {0} transcript has been created for a ticket you participated in.",
"createdActiveAdmin":"A new {0} transcript has been created in one of the tickets you participated as admin!", "createdActiveAdmin":"A new {0} transcript has been created for a ticket you participated in as an admin.",
"createdEveryAdmin":"A new {0} transcript has been created in one of the tickets you were admin in!", "createdEveryAdmin":"A new {0} transcript has been created for a ticket you managed as an admin.",
"createdOther":"A new {0} transcript has been created!" "createdOther":"A new {0} transcript has been created."
}, },
"errors":{ "errors":{
"retry":"Retry", "retry":"Retry",
"continue":"Delete Without Transcript", "continue":"Delete Without Transcript",
"backup":"Create Backup Transcript", "backup":"Create Backup Transcript",
"error":"Something went wrong while trying to create the transcript.\nWhat would you like to do?\n\nThis ticket won't be deleted until you click one of these buttons.", "error":"Something went wrong while creating the transcript.\nWhat would you like to do?\n\nThis ticket will not be deleted until you select one of the options below.",
"title":"Transcript Error" "title":"Transcript Error"
}, },
"text":{ "text":{
@@ -279,7 +279,7 @@
"fileTitle":"FILE", "fileTitle":"FILE",
"fieldsTitle":"FIELDS", "fieldsTitle":"FIELDS",
"reactionsTitle":"REACTIONS", "reactionsTitle":"REACTIONS",
"statsTitle":"STATS", "statsTitle":"STATISTICS",
"emptyContent":"<content is empty>", "emptyContent":"<content is empty>",
"noTitle":"<no-title>", "noTitle":"<no-title>",
"noDesc":"<no-description>" "noDesc":"<no-description>"
@@ -302,68 +302,68 @@
"permissionError":"Permission Error" "permissionError":"Permission Error"
}, },
"descriptions":{ "descriptions":{
"askForInfo":"Contact the owner of this bot for more info!", "askForInfo":"Please contact the bot owner for more information.",
"askForInfoResolve":"Contact the bot owner of this bot if this issue doesn't resolve after a few tries.", "askForInfoResolve":"If the issue persists after a few attempts, please contact the bot owner.",
"internalError":"Failed to respond to this {0} due to an internal error!", "internalError":"An internal error occurred while processing this {0}.",
"optionMissing":"A required parameter is missing in this command!", "optionMissing":"A required parameter is missing for this command.",
"optionInvalid":"A parameter in this command is invalid!", "optionInvalid":"One or more parameters provided for this command are invalid.",
"optionInvalidChoose":"Choose between", "optionInvalidChoose":"Please choose between",
"unknownCommand":"Try visiting the help menu for more info!", "unknownCommand":"Please use the help menu for more information.",
"noPermissions":"You are not allowed to use this {0}!", "noPermissions":"You are not permitted to use this {0}.",
"noPermissionsList":"Required Permissions: (one of them)", "noPermissionsList":"Required permissions (one of the following):",
"noPermissionsCooldown":"You are not allowed to use this {0} because you have a cooldown!", "noPermissionsCooldown":"You cannot use this {0} while on cooldown.",
"noPermissionsBlacklist":"You are not allowed to use this {0} because you have been blacklisted!", "noPermissionsBlacklist":"You cannot use this {0} because you are blacklisted.",
"noPermissionsLimitGlobal":"You are not allowed to create a ticket because the server reached the max tickets limit!", "noPermissionsLimitGlobal":"You cannot create a ticket because the server has reached its maximum ticket limit.",
"noPermissionsLimitGlobalUser":"You are not allowed to create a ticket because you reached the max tickets limit!", "noPermissionsLimitGlobalUser":"You cannot create a ticket because you have reached your maximum ticket limit.",
"noPermissionsLimitOption":"You are not allowed to create a ticket because the server reached the max tickets limit for this option!", "noPermissionsLimitOption":"You cannot create a ticket because the server has reached the maximum ticket limit for this option.",
"noPermissionsLimitOptionUser":"You are not allowed to create a ticket because you reached the max tickets limit for this option!", "noPermissionsLimitOptionUser":"You cannot create a ticket because you have reached the maximum ticket limit for this option.",
"unknownTicket":"Try this command again in a valid ticket!", "unknownTicket":"Please run this command inside a valid ticket channel.",
"deprecatedTicket":"The current channel is not a valid ticket! It might have been a ticket from an old Open Ticket version!", "deprecatedTicket":"This channel is not recognized as a valid ticket. It may have been created with an older version of the bot.",
"notInGuild":"This {0} doesn't work in DM! Please try it again in a server!", "notInGuild":"This {0} cannot be used in direct messages. Please use it in a server.",
"channelRename":"Due to discord ratelimits, it's currently impossible for the bot to rename the channel. The channel will automatically be renamed over 10 minutes if the bot isn't rebooted.", "channelRename":"Due to Discord rate limits, the channel could not be renamed immediately. It will be renamed automatically within 10 minutes if the bot remains online.",
"channelRenameSource":"The source of this error is: {0}", "channelRenameSource":"Error source: {0}",
"busy":"Unable to use this {0}!\nThe ticket is currently being processed by the bot.\n\nPlease try again in a few seconds!", "busy":"This {0} is currently unavailable.\nThe ticket is being processed by the bot.\n\nPlease try again in a few seconds.",
"closeBeforeMessage":"This ticket cannot be closed/deleted before a message has been sent by a user.", "closeBeforeMessage":"This ticket cannot be closed or deleted before a user has sent a message.",
"closeBeforeAdminMessage":"This ticket cannot be closed/deleted before a message has been sent by a ticket admin or support member.", "closeBeforeAdminMessage":"This ticket cannot be closed or deleted before a support member or admin has sent a message.",
"unableToCreateTicket":"You are unable to create a ticket." "unableToCreateTicket":"You are currently unable to create a ticket."
}, },
"optionInvalidReasons":{ "optionInvalidReasons":{
"stringRegex":"Value doesn't match pattern!", "stringRegex":"The value does not match the required pattern.",
"stringMinLength":"Value needs to be at least {0} characters!", "stringMinLength":"The value must be at least {0} characters long.",
"stringMaxLength":"Value needs to be at most {0} characters!", "stringMaxLength":"The value must be at most {0} characters long.",
"numberInvalid":"Invalid number!", "numberInvalid":"Invalid number provided.",
"numberMin":"Number needs to be at least {0}!", "numberMin":"The number must be at least {0}.",
"numberMax":"Number needs to be at most {0}!", "numberMax":"The number must be at most {0}.",
"numberDecimal":"Number is not allowed to be a decimal!", "numberDecimal":"Decimals are not allowed.",
"numberNegative":"Number is not allowed to be negative!", "numberNegative":"Negative numbers are not allowed.",
"numberPositive":"Number is not allowed to be positive!", "numberPositive":"Positive numbers are not allowed.",
"numberZero":"Number is not allowed to be zero!", "numberZero":"Zero is not allowed.",
"channelNotFound":"Unable to find channel!", "channelNotFound":"Channel not found.",
"userNotFound":"Unable to find user!", "userNotFound":"User not found.",
"roleNotFound":"Unable to find role!", "roleNotFound":"Role not found.",
"memberNotFound":"Unable to find user!", "memberNotFound":"Member not found.",
"mentionableNotFound":"Unable to find user or role!", "mentionableNotFound":"User or role not found.",
"channelType":"Invalid channel type!", "channelType":"Invalid channel type.",
"notInGuild":"This option requires you to be in a server!" "notInGuild":"This option can only be used in a server."
}, },
"permissions":{ "permissions":{
"developer":"You need to be the developer of the bot.", "developer":"This action is restricted to the bot developer.",
"owner":"You need to be the server owner.", "owner":"You must be the server owner to use this.",
"admin":"You need to be a server admin.", "admin":"You must have administrator permissions to use this.",
"moderator":"You need to be a moderator.", "moderator":"You must be a moderator to use this.",
"support":"You need to be in the support team.", "support":"You must be part of the support team to use this.",
"member":"You need to be a member.", "member":"You must be a server member to use this.",
"discord-administrator":"You need to have the `ADMINISTRATOR` permission." "discord-administrator":"You must have the `ADMINISTRATOR` permission."
}, },
"actionInvalid":{ "actionInvalid":{
"close":"Ticket is already closed!", "close":"This ticket is already closed.",
"reopen":"Ticket is not closed yet!", "reopen":"This ticket is not closed.",
"claim":"Ticket is already claimed!", "claim":"This ticket is already claimed.",
"unclaim":"Ticket is not claimed yet!", "unclaim":"This ticket is not claimed.",
"pin":"Ticket is already pinned!", "pin":"This ticket is already pinned.",
"unpin":"Ticket is not pinned yet!", "unpin":"This ticket is not pinned.",
"add":"This user is already able to access the ticket!", "add":"This user already has access to this ticket.",
"remove":"Unable to remove this user from the ticket!" "remove":"This user does not have access to this ticket."
} }
}, },
"params":{ "params":{
@@ -432,107 +432,107 @@
} }
}, },
"commands":{ "commands":{
"reason":"Specify an optional reason that will be visible in logs.", "reason":"Optional reason shown in logs.",
"help":"Get a list of all the available commands.", "help":"Display all available commands.",
"panel":"Spawn a message with a dropdown or buttons (for ticket creation).", "panel":"Create a ticket panel (buttons or dropdown).",
"panelId":"The identifier of the panel that you want to spawn.", "panelId":"ID of the panel to spawn.",
"panelAutoUpdate":"Do you want this panel to automatically update when edited?", "panelAutoUpdate":"Automatically update this panel when edited.",
"ticket":"Instantly create a ticket.", "ticket":"Create a ticket instantly.",
"ticketId":"The identifier of the ticket that you want to create.", "ticketId":"ID of the ticket to create.",
"close":"Close a ticket.", "close":"Close this ticket.",
"delete":"Delete a ticket.", "delete":"Delete this ticket.",
"deleteNoTranscript":"Delete this ticket without creating a transcript.", "deleteNoTranscript":"Delete ticket without saving a transcript.",
"reopen":"Reopen a ticket.", "reopen":"Reopen a closed ticket.",
"claim":"Claim a ticket.", "claim":"Claim this ticket.",
"claimUser":"Claim this ticket to someone else instead of yourself.", "claimUser":"Claim the ticket for another user.",
"unclaim":"Unclaim a ticket.", "unclaim":"Unclaim this ticket.",
"pin":"Pin a ticket.", "pin":"Pin this ticket.",
"unpin":"Unpin a ticket.", "unpin":"Unpin this ticket.",
"move":"Move a ticket.", "move":"Move ticket to another option.",
"moveId":"The identifier of the option that you want to move to.", "moveId":"Target option ID.",
"rename":"Rename a ticket.", "rename":"Rename this ticket.",
"renameName":"The new name for this ticket.", "renameName":"New name for the ticket.",
"add":"Add a user to a ticket.", "add":"Add a user to this ticket.",
"addUser":"The user to add.", "addUser":"User to add.",
"remove":"Remove a user from a ticket.", "remove":"Remove a user from this ticket.",
"removeUser":"The user to remove.", "removeUser":"User to remove.",
"blacklist":"Manage the ticket blacklist.", "blacklist":"Manage the blacklist.",
"blacklistView":"View a list of the current blacklist.", "blacklistView":"View all blacklisted users.",
"blacklistAdd":"Add a user to the blacklist.", "blacklistAdd":"Add a user to the blacklist.",
"blacklistRemove":"Remove a user from the blacklist.", "blacklistRemove":"Remove a user from the blacklist.",
"blacklistGet":"Get the details from a blacklisted user.", "blacklistGet":"View blacklist entry details.",
"blacklistGetUser":"The user to get details from.", "blacklistGetUser":"User to look up.",
"stats":"View statistics from the bot, a member or a ticket.", "stats":"View bot, user or ticket statistics.",
"statsReset":"Reset all the stats of the bot (and start counting from zero).", "statsReset":"Reset all bot statistics.",
"statsGlobal":"View the global stats.", "statsGlobal":"View global bot statistics.",
"statsUser":"View the stats from a user in the server.", "statsUser":"View a user's statistics.",
"statsUserUser":"The user to view.", "statsUserUser":"User to view.",
"statsTicket":"View the stats of a ticket in the server.", "statsTicket":"View ticket statistics.",
"statsTicketTicket":"The ticket to view.", "statsTicketTicket":"Ticket to view.",
"clear":"Delete multiple tickets at the same time.", "clear":"Delete multiple tickets at once.",
"clearFilter":"The filter for clearing tickets.", "clearFilter":"Filter used when clearing tickets.",
"clearFilters":{ "clearFilters":{
"all":"All", "all":"All tickets",
"open":"Open", "open":"Open tickets",
"close":"Closed", "close":"Closed tickets",
"claim":"Claimed", "claim":"Claimed tickets",
"unclaim":"Unclaimed", "unclaim":"Unclaimed tickets",
"pin":"Pinned", "pin":"Pinned tickets",
"unpin":"Unpinned", "unpin":"Unpinned tickets",
"autoclose":"Autoclosed" "autoclose":"Autoclosed tickets"
}, },
"autoclose":"Manage autoclose in a ticket.", "autoclose":"Manage ticket autoclose.",
"autocloseDisable":"Disable autoclose in this ticket.", "autocloseDisable":"Disable autoclose.",
"autocloseEnable":"Enable autoclose in this ticket.", "autocloseEnable":"Enable autoclose.",
"autocloseEnableTime":"The amount of hours this ticket needs to be inactive to close it.", "autocloseEnableTime":"Hours of inactivity before closing.",
"autodelete":"Manage autodelete in a ticket.", "autodelete":"Manage ticket autodelete.",
"autodeleteDisable":"Disable autodelete in this ticket.", "autodeleteDisable":"Disable autodelete.",
"autodeleteEnable":"Enable autodelete in this ticket.", "autodeleteEnable":"Enable autodelete.",
"autodeleteEnableTime":"The amount of days this ticket needs to be inactive to delete it.", "autodeleteEnableTime":"Days of inactivity before deletion.",
"topic":"Manage the topic of the ticket channel.", "topic":"Manage ticket channel topic.",
"topicSet":"Set the topic of the ticket channel.", "topicSet":"Set the ticket channel topic.",
"topicValue":"The new topic of the channel.", "topicValue":"New channel topic text.",
"topicList":"Get a list of all tickets with their topic and stats.", "topicList":"List all ticket channel topics.",
"priority":"Manage the priority of the ticket.", "priority":"Manage ticket priority.",
"prioritySet":"Set the priority of the ticket.", "prioritySet":"Set ticket priority.",
"priorityValue":"The priority of the channel.", "priorityValue":"Priority level.",
"priorityGet":"Get the priority of the ticket.", "priorityGet":"View ticket priority.",
"priorityList":"Get a list of all tickets with their priority status.", "priorityList":"List all ticket priorities.",
"transfer":"Transfer the ticket ownership from one user to another.", "transfer":"Transfer ticket ownership.",
"transferUser":"The user to transfer to." "transferUser":"User to transfer to."
}, },
"helpMenu":{ "helpMenu":{
"help":"Get a list of all the available commands.", "help":"View all available commands.",
"ticket":"Instantly create a ticket.", "ticket":"Create a ticket instantly.",
"close":"Close a ticket, this disables writing in this channel.", "close":"Close this ticket and disable messaging in the channel.",
"delete":"Delete a ticket, this creates a transcript when enabled.", "delete":"Delete this ticket (creates a transcript if enabled).",
"reopen":"Reopen a ticket, this enables writing in this channel again.", "reopen":"Reopen a closed ticket and restore messaging.",
"pin":"Pin a ticket. This will move the ticket to the top and will add a '📌' emoij to the name.", "pin":"Pin this ticket and move it to the top with '📌'.",
"unpin":"Unpin a ticket. The ticket will stay on it's position but will lose the '📌' emoij.", "unpin":"Unpin this ticket and remove the '📌' emoji.",
"move":"Move a ticket. This will change the type of this ticket.", "move":"Move this ticket to a different option or ticket type.",
"rename":"Rename a ticket. This will change the channel name of this ticket.", "rename":"Rename this ticket channel.",
"claim":"Claim a ticket. With this, you can let your team know you are handling this ticket.", "claim":"Claim this ticket to show you are handling it.",
"unclaim":"Unclaim a ticket. With this, you can let your team know that this ticket is free again.", "unclaim":"Unclaim this ticket to mark it as available.",
"add":"Add a user to a ticket. This will allow the user to read & write in this ticket.", "add":"Add a user to this ticket.",
"remove":"Remove a user from a ticket. This will remove the ability to read & write for a user in this ticket.", "remove":"Remove a user's access from this ticket.",
"panel":"Spawn a message with a dropdown or buttons (for ticket creation).", "panel":"Create a ticket panel with buttons or a dropdown.",
"blacklistView":"View a list of the current blacklist.", "blacklistView":"View all blacklisted users.",
"blacklistAdd":"Add a user to the blacklist.", "blacklistAdd":"Add a user to the blacklist.",
"blacklistRemove":"Remove a user from the blacklist.", "blacklistRemove":"Remove a user from the blacklist.",
"blacklistGet":"Get the details from a blacklisted user.", "blacklistGet":"View details of a blacklisted user.",
"statsGlobal":"View the global stats.", "statsGlobal":"View global bot statistics.",
"statsTicket":"View the stats of a ticket in the server.", "statsTicket":"View statistics for a ticket.",
"statsUser":"View the stats from a user in the server.", "statsUser":"View statistics for a user.",
"statsReset":"Reset all the stats of the bot (and start counting from zero).", "statsReset":"Reset all bot statistics.",
"autocloseDisable":"Disable autoclose in this ticket.", "autocloseDisable":"Disable autoclose for this ticket.",
"autocloseEnable":"Enable autoclose in this ticket.", "autocloseEnable":"Enable autoclose for this ticket.",
"autodeleteDisable":"Disable autodelete in this ticket.", "autodeleteDisable":"Disable autodelete for this ticket.",
"autodeleteEnable":"Enable autodelete in this ticket.", "autodeleteEnable":"Enable autodelete for this ticket.",
"categories":{ "categories":{
"general":"General Commands", "general":"General Commands",
"basicTicket":"Basic Ticket Commands", "basicTicket":"Basic Ticket Commands",
@@ -545,10 +545,10 @@
}, },
"stats":{ "stats":{
"scopes":{ "scopes":{
"global":"Global Stats", "global":"Global Statistics",
"system":"System Stats", "system":"System Statistics",
"user":"User Stats", "user":"User Statistics",
"ticket":"Ticket Stats", "ticket":"Ticket Statistics",
"participants":"Participants", "participants":"Participants",
"messages":"Messages" "messages":"Messages"
}, },
@@ -592,9 +592,9 @@
} }
}, },
"panel":{ "panel":{
"selectTicket":"Select your ticket", "selectTicket":"Select a ticket",
"selectRole":"Select your role", "selectRole":"Select a role",
"selectOption":"Select your option" "selectOption":"Select an option"
}, },
"priorities":{ "priorities":{
"urgent":"Urgent", "urgent":"Urgent",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["iamnotmega","ChatGPT"], "translators":["iamnotmega","ChatGPT"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Estonian", "language":"Estonian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["iamnotmega","ChatGPT"], "translators":["iamnotmega","ChatGPT"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Finnish", "language":"Finnish",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["guillee3"], "translators":["guillee3"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"French", "language":"French",
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["benzorich"], "translators":["benzorich"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"German", "language":"German",
@@ -14,8 +14,8 @@
"typeInfo":"[INFO]", "typeInfo":"[INFO]",
"headerConfigChecker":"CONFIG CHECKER", "headerConfigChecker":"CONFIG CHECKER",
"headerDescription":"Prüfen Sie auf Fehler in Ihrer Konfigurationsdateien!", "headerDescription":"Prüfen Sie auf Fehler in Ihrer Konfigurationsdateien!",
"footerError":"Der Bot wird nicht starten, bis alle {0}'s repariert sind!", "footerError":"Der Bot wird nicht starten, bis alle {0}en repariert sind!",
"footerWarning":"Es wird empfohlen, vor dem Start alle {0}'s zu korrigieren!", "footerWarning":"Es wird empfohlen, vor dem Start alle {0}en zu korrigieren!",
"footerSupport":"SUPPORT: {0} - DOCS: {1}", "footerSupport":"SUPPORT: {0} - DOCS: {1}",
"compactInformation":"Verwenden Sie {0} für weitere Informationen!", "compactInformation":"Verwenden Sie {0} für weitere Informationen!",
"dataPath":"Pfad", "dataPath":"Pfad",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"], "translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Greek", "language":"Greek",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["challenger_nova"], "translators":["challenger_nova"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Hindi", "language":"Hindi",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["Kornel0706"], "translators":["Kornel0706"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Hungarian", "language":"Hungarian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["erxg"], "translators":["erxg"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Indonesian", "language":"Indonesian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["fraden1mvp.","imperatorix_17"], "translators":["fraden1mvp.","imperatorix_17"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Italian", "language":"Italian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"], "translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Japanese", "language":"Japanese",
+598 -598
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"], "translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Korean", "language":"Korean",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"], "translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Kurdish", "language":"Kurdish",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["NoOneNook"], "translators":["NoOneNook"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Latvian", "language":"Latvian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["TsgIndrius"], "translators":["TsgIndrius"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Lithuanian", "language":"Lithuanian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["NoOneNook"], "translators":["NoOneNook"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Norwegian", "language":"Norwegian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["dysashop","zhavis"], "translators":["dysashop","zhavis"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Persian", "language":"Persian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["DanoGlez"], "translators":["DanoGlez"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Polish", "language":"Polish",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["quiradon"], "translators":["quiradon"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Portuguese", "language":"Portuguese",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["SankeDev"], "translators":["SankeDev"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Romanian", "language":"Romanian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["NoOneNook"], "translators":["NoOneNook"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Russian", "language":"Russian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"], "translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Simplified Chainese", "language":"Simplified Chainese",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"], "translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Solvenian", "language":"Solvenian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["Redactado","Josuens"], "translators":["Redactado","Josuens"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Spanish", "language":"Spanish",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["NoOneNook"], "translators":["NoOneNook"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Svenska", "language":"Svenska",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"], "translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Tamil", "language":"Tamil",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["modshd"], "translators":["modshd"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Thai", "language":"Thai",
+608
View File
@@ -0,0 +1,608 @@
{
"_TRANSLATION":{
"otversion":"v4.2.0",
"translators":["me.october"],
"lastedited":"10/03/2026",
"language":"Traditional Chinese",
"automated":false
},
"checker":{
"system":{
"typeError":"[錯誤]",
"headerOpenTicket":"開啟工單",
"typeWarning":"[警告]",
"typeInfo":"[信息]",
"headerConfigChecker":"配置檢查器",
"headerDescription":"檢查您的配置文件中的錯誤!",
"footerError":"機器人將無法啟動,直到所有{0}錯誤被修複!",
"footerWarning":"建議在啟動前修複所有{0}警告!",
"footerSupport":"支援:{0} - 文檔:{1}",
"compactInformation":"使用{0}獲取更多信息!",
"dataPath":"路徑",
"dataDocs":"文檔",
"dataMessages":"消息"
},
"messages":{
"stringTooShort":"此字符串不能少於{0}個字符!",
"stringTooLong":"此字符串不能超過{0}個字符!",
"stringLengthInvalid":"此字符串長度必須為{0}個字符!",
"stringStartsWith":"此字符串必須以{0}開頭!",
"stringEndsWith":"此字符串必須以{0}結尾!",
"stringContains":"此字符串必須包含{0}!",
"stringChoices":"此字符串隻能是以下值之一:{0}!",
"stringRegex":"此字符串無效!",
"stringInvertedContains":"此字符串不能包含 {0}!",
"stringLowercase":"此字符串必須全部使用小寫字母!",
"stringUppercase":"此字符串必須全部使用大寫字母!",
"stringSpecialCharacters":"此字符串不能包含任何特殊字符!(僅允許 a-z、0-9 和空格)",
"stringNoSpaces":"此字符串不能包含空格!",
"stringCapitalWord":"建議此字符串中的每個單詞都以大寫字母開頭!",
"stringCapitalSentence":"此字符串中的某些句子似乎冇有以大寫字母開頭!",
"stringPunctuation":"此字符串中的句子似乎冇有以標點符號結尾!",
"numberTooShort":"此數字不能少於{0}位!",
"numberTooLong":"此數字不能超過{0}位!",
"numberLengthInvalid":"此數字長度必須為{0}位!",
"numberTooSmall":"此數字至少為{0}!",
"numberTooLarge":"此數字最多為{0}!",
"numberNotEqual":"此數字必須為{0}!",
"numberStep":"此數字必須是{0}的倍數!",
"numberStepOffset":"此數字必須是{0}的倍數,起始值為{1}!",
"numberStartsWith":"此數字必須以{0}開頭!",
"numberEndsWith":"此數字必須以{0}結尾!",
"numberContains":"此數字必須包含{0}!",
"numberChoices":"此數字隻能是以下值之一:{0}!",
"numberFloat":"此數字不能為小數!",
"numberNegative":"此數字不能為負數!",
"numberPositive":"此數字不能為正數!",
"numberZero":"此數字不能為零!",
"numberNan":"此數字不能為 NaN(非數字)!",
"numberInvertedContains":"此數字不能包含 {0}!",
"booleanTrue":"此佈爾值不能為真!",
"booleanFalse":"此佈爾值不能為假!",
"arrayEmptyDisabled":"此數組不允許為空!",
"arrayEmptyRequired":"此數組必須為空!",
"arrayTooShort":"此數組長度至少為{0}!",
"arrayTooLong":"此數組長度最多為{0}!",
"arrayLengthInvalid":"此數組長度必須為{0}!",
"arrayInvalidTypes":"此數組隻能包含以下類型:{0}!",
"arrayDouble":"此數組不允許重複值!",
"discordInvalidId":"這是無效的Discord {0} ID!",
"discordInvalidIdOptions":"這是無效的Discord {0} ID!您還可以使用以下之一:{1}!",
"discordInvalidToken":"這是無效的Discord令牌(文法上)!",
"colorInvalid":"這是無效的十六進製顔色!",
"emojiTooShort":"此字符串至少需要{0}個錶情符號!",
"emojiTooLong":"此字符串最多隻能有{0}個錶情符號!",
"emojiCustom":"此錶情符號不能是自定義Discord錶情符號!",
"emojiInvalid":"這是無效的錶情符號!",
"urlInvalid":"此URL無效!",
"urlInvalidHttp":"This url can only use the https:// protocol!",
"urlInvalidProtocol":"This url can only use the http:// & https:// protocols!",
"urlInvalidHostname":"此URL的主機名不被允許!",
"urlInvalidExtension":"此URL的擴展名無效!請選擇:{0}!",
"urlInvalidPath":"此URL的路徑無效!",
"idNotUnique":"此ID不唯一,請使用其他ID!",
"idNonExistent":"ID {0}不存在!",
"invalidType":"此屬性必須為類型:{0}!",
"propertyMissing":"此對象缺少屬性{0}!",
"propertyOptional":"此對象中的屬性{0}是可選的!",
"objectDisabled":"此對象已禁用,請使用{0}啟用!",
"nullInvalid":"此屬性不能為null!",
"switchInvalidType":"此屬性必須是以下類型之一:{0}!",
"objectSwitchInvalid":"此對象必須是以下類型之一:{0}!",
"invalidLanguage":"這是無效的語言!",
"invalidButton":"此按鈕必須至少有一個{0}或{1}!",
"unusedOption":"選項{0}未在任何地方使用!",
"unusedQuestion":"問題{0}未在任何地方使用!",
"dropdownOption":"啟用下拉菜單的麵闆隻能包含“ticket”類型的選項!",
"customInvalidVersion":"配置文件中指定的版本不匹配!請確保您已將配置更新至最新版本!"
}
},
"actions":{
"buttons":{
"create":"訪問工單",
"close":"關閉工單",
"delete":"刪除工單",
"reopen":"重新開啟工單",
"claim":"認領工單",
"unclaim":"取消認領工單",
"pin":"置頂工單",
"unpin":"取消置頂工單",
"clear":"刪除工單",
"helpSwitchSlash":"檢視斜杠命令",
"helpSwitchText":"檢視文本命令",
"helpPage":"第{0}頁",
"withReason":"帶原因",
"withoutTranscript":"不帶記錄"
},
"titles":{
"created":"工單已創建",
"close":"工單已關閉",
"delete":"工單已刪除",
"reopen":"工單已重新開啟",
"claim":"工單已認領",
"unclaim":"工單已取消認領",
"pin":"工單已置頂",
"unpin":"工單已取消置頂",
"rename":"工單已重命名",
"move":"工單已移動",
"add":"工單用戶已添加",
"remove":"工單用戶已移除",
"help":"可用命令",
"statsReset":"重置統計",
"blacklistAdd":"用戶已拉黑",
"blacklistRemove":"用戶已解禁",
"blacklistGet":"已拉黑用戶",
"blacklistView":"當前黑名單",
"blacklistAddDm":"已加入黑名單",
"blacklistRemoveDm":"已從黑名單移除",
"clear":"工單已清除",
"clearTickets":"清除工單",
"roles":"角色已更新",
"autoclose":"工單自動關閉",
"autocloseEnabled":"自動關閉已啟用",
"autocloseDisabled":"自動關閉已禁用",
"autodelete":"工單自動刪除",
"autodeleteEnabled":"自動刪除已啟用",
"autodeleteDisabled":"自動刪除已禁用",
"topicSet":"主題已更改",
"prioritySet":"優先級已更改",
"priorityGet":"工單優先級",
"transfer":"工單已轉移"
},
"descriptions":{
"create":"您的工單已創建。點選下方按鈕訪問!",
"close":"工單已成功關閉!",
"delete":"工單已成功刪除!",
"reopen":"工單已成功重新開啟!",
"claim":"工單已成功認領!",
"unclaim":"工單已成功取消認領!",
"pin":"工單已成功置頂!",
"unpin":"工單已成功取消置頂!",
"rename":"工單已成功重命名為{0}!",
"move":"工單已成功移動到{0}!",
"add":"{0}已成功添加到工單!",
"remove":"{0}已成功從工單移除!",
"helpExplanation":"`<名稱>` => 必填參數\n`[名稱]` => 可選參數",
"statsReset":"機器人統計已成功重置!",
"statsError":"無法檢視工單統計!\n{0}不是工單!",
"blacklistAdd":"{0}已成功拉黑!",
"blacklistRemove":"{0}已成功解禁!",
"blacklistGetSuccess":"{0}當前已被拉黑!",
"blacklistGetEmpty":"{0}當前未被拉黑!",
"blacklistViewEmpty":"尚未有人被拉黑!",
"blacklistViewTip":"使用“/blacklist add”拉黑用戶!",
"clearVerify":"確定要刪除多個工單嗎?\n此操作無法撤銷!",
"clearReady":"{0}個工單已成功刪除!",
"rolesEmpty":"未更新任何角色!",
"autocloseLeave":"此工單已自動關閉,因為創建者離開了服務器!",
"autocloseTimeout":"此工單已自動關閉,因為它已超過`{0}小時`未活動!",
"autodeleteLeave":"此工單已自動刪除,因為創建者離開了服務器!",
"autodeleteTimeout":"此工單已自動刪除,因為它已超過`{0}天`未活動!",
"autocloseEnabled":"此工單已啟用自動關閉!\n超過`{0}小時`未活動後將自動關閉!",
"autocloseDisabled":"此工單已禁用自動關閉!\n不再自動關閉!",
"autodeleteEnabled":"此工單已啟用自動刪除!\n超過`{0}天`未活動後將自動刪除!",
"autodeleteDisabled":"此工單已禁用自動刪除!\n不再自動刪除!",
"ticketMessageLimit":"您隻能同時創建{0}個工單!",
"ticketMessageAutoclose":"此工單將在超過{0}小時未活動後自動關閉!",
"ticketMessageAutodelete":"此工單將在超過{0}天未活動後自動刪除!",
"panelReady":"麵闆已在後續消息中可用!\n此消息現在可以刪除!",
"topicSet":"頻道主題已由 {0} 成功更改!",
"prioritySet":"工單優先級已由 {1} 成功更改為 {0}!",
"priorityGet":"此工單當前的優先級為 {0}。",
"transfer":"工單所有權已由 {2} 成功從 {0} 轉移至 {1}!"
},
"modal":{
"closePlaceholder":"您為什麼關閉此工單?",
"deletePlaceholder":"您為什麼刪除此工單?",
"reopenPlaceholder":"您為什麼重新開啟此工單?",
"claimPlaceholder":"您為什麼認領此工單?",
"unclaimPlaceholder":"您為什麼取消認領此工單?",
"pinPlaceholder":"您為什麼置頂此工單?",
"unpinPlaceholder":"您為什麼取消置頂此工單?"
},
"logs":{
"createLog":"{0}創建了一個新工單!",
"closeLog":"此工單已被{0}關閉!",
"closeDm":"您的工單已在我們的服務器中關閉!",
"deleteLog":"此工單已被{0}刪除!",
"deleteDm":"您的工單已在我們的服務器中刪除!",
"reopenLog":"此工單已被{0}重新開啟!",
"reopenDm":"您的工單已在我們的服務器中重新開啟!",
"claimLog":"此工單已被{0}認領!",
"claimDm":"您的工單已在我們的服務器中被認領!",
"unclaimLog":"此工單已被{0}取消認領!",
"unclaimDm":"您的工單已在我們的服務器中取消認領!",
"pinLog":"此工單已被{0}置頂!",
"pinDm":"您的工單已在我們的服務器中置頂!",
"unpinLog":"此工單已被{0}取消置頂!",
"unpinDm":"您的工單已在我們的服務器中取消置頂!",
"renameLog":"此工單已被{1}重命名為{0}!",
"renameDm":"您的工單已在我們的服務器中重命名為{0}!",
"moveLog":"此工單已被{1}移動到{0}!",
"moveDm":"您的工單已在我們的服務器中移動到{0}!",
"addLog":"{0}已被{1}添加到此工單!",
"addDm":"{0}已被添加到您的工單中!",
"removeLog":"{0}已被{1}從此工單移除!",
"removeDm":"{0}已被從您的工單中移除!",
"blacklistAddLog":"{0}被{1}拉黑!",
"blacklistRemoveLog":"{0}被{1}從黑名單移除!",
"blacklistAddDm":"您已被我們的服務器拉黑!\n從現在起,您無法創建工單!",
"blacklistRemoveDm":"您已被我們的服務器解禁!\n現在您可以再次創建工單!",
"clearLog":"{0}個工單已被{1}刪除!",
"transferLog":"此工單的所有權已由 {2} 從 {0} 轉移至 {1}!",
"transferDm":"您在服務器中的工單所有權已從 {0} 轉移至 {1}!",
"prioritySetLog":"此工單的優先級已由 {1} 更改為 {0}!",
"prioritySetDm":"您在服務器中的工單優先級已更改為 {0}!",
"roleUpdateLog":"{0} 已更新其角色!",
"roleUpdateDm":"您在服務器中的角色已更新!"
}
},
"transcripts":{
"success":{
"visit":"檢視記錄",
"ready":"記錄已創建",
"textFileDescription":"這是已刪除工單的文本記錄!",
"htmlProgress":"請等待此HTML記錄處理完成...",
"createdChannel":"服務器中已創建一個新的{0}記錄!",
"createdCreator":"已為您的工單創建一個新的{0}記錄!",
"createdParticipant":"您參與的工單中已創建一個新的{0}記錄!",
"createdActiveAdmin":"您作為管理員參與的工單中已創建一個新的{0}記錄!",
"createdEveryAdmin":"您曾擔任管理員的工單中已創建一個新的{0}記錄!",
"createdOther":"已創建一個新的{0}記錄!"
},
"errors":{
"retry":"重試",
"continue":"刪除無記錄",
"backup":"創建備份記錄",
"error":"創建記錄時出錯。\n您想怎麼做?\n\n在您點選以下按鈕之前,此工單不會被刪除。",
"title":"記錄錯誤"
},
"text":{
"messagesTitle":"消息",
"embedTitle":"EMBED",
"fileTitle":"文件",
"fieldsTitle":"字段",
"reactionsTitle":"反應",
"statsTitle":"統計",
"emptyContent":"<內容為空>",
"noTitle":"<無標題>",
"noDesc":"<無描述>"
}
},
"errors":{
"titles":{
"internalError":"內部錯誤",
"optionMissing":"命令選項缺失",
"optionInvalid":"命令選項無效",
"unknownCommand":"未知命令",
"noPermissions":"無權限",
"unknownTicket":"未知工單",
"deprecatedTicket":"過時工單",
"unknownOption":"未知選項",
"unknownPanel":"未知麵闆",
"notInGuild":"不在服務器中",
"channelRename":"無法重命名頻道",
"busy":"工單繁忙",
"permissionError":"權限錯誤"
},
"descriptions":{
"askForInfo":"請聯係此機器人的所有者獲取更多信息!",
"askForInfoResolve":"如果此問題在多次嘗試後仍未解決,請聯係此機器人的所有者。",
"internalError":"由於內部錯誤,無法回響此{0}!",
"optionMissing":"此命令缺少必填參數!",
"optionInvalid":"此命令中的參數無效!",
"optionInvalidChoose":"請選擇",
"unknownCommand":"請訪問幫助菜單獲取更多信息!",
"noPermissions":"您無權使用此{0}!",
"noPermissionsList":"所需權限:(其中之一)",
"noPermissionsCooldown":"您因冷卻時間無法使用此{0}!",
"noPermissionsBlacklist":"您因被拉黑無法使用此{0}!",
"noPermissionsLimitGlobal":"您無法創建工單,因為服務器已達到最大工單限製!",
"noPermissionsLimitGlobalUser":"您無法創建工單,因為您已達到最大工單限製!",
"noPermissionsLimitOption":"您無法創建工單,因為服務器已達到此選項的最大工單限製!",
"noPermissionsLimitOptionUser":"您無法創建工單,因為您已達到此選項的最大工單限製!",
"unknownTicket":"請在有效工單中重試此命令!",
"deprecatedTicket":"當前頻道不是有效工單!可能是舊版Open Ticket的工單!",
"notInGuild":"此{0}在私信中無效!請在服務器中重試!",
"channelRename":"由於Discord速率限製,機器人目前無法重命名頻道。如果機器人未重啟,頻道將在10分鍾後自動重命名。",
"channelRenameSource":"此錯誤的來源是:{0}",
"busy":"無法使用此{0}!\n工單當前正在被機器人處理。\n\n請幾秒後重試!",
"closeBeforeMessage":"用戶發送消息之前,無法關閉或刪除此工單。",
"closeBeforeAdminMessage":"工單管理員或支援成員發送消息之前,無法關閉或刪除此工單。",
"unableToCreateTicket":"您無法創建工單。"
},
"optionInvalidReasons":{
"stringRegex":"值不符合模式!",
"stringMinLength":"值至少需要{0}個字符!",
"stringMaxLength":"值最多需要{0}個字符!",
"numberInvalid":"無效數字!",
"numberMin":"數字至少為{0}!",
"numberMax":"數字最多為{0}!",
"numberDecimal":"數字不能為小數!",
"numberNegative":"數字不能為負數!",
"numberPositive":"數字不能為正數!",
"numberZero":"數字不能為零!",
"channelNotFound":"無法找到頻道!",
"userNotFound":"無法找到用戶!",
"roleNotFound":"無法找到角色!",
"memberNotFound":"無法找到用戶!",
"mentionableNotFound":"無法找到用戶或角色!",
"channelType":"無效的頻道類型!",
"notInGuild":"此選項需要您在服務器中!"
},
"permissions":{
"developer":"您需要是機器人的開發者。",
"owner":"您需要是服務器所有者。",
"admin":"您需要是服務器管理員。",
"moderator":"您需要是版主。",
"support":"您需要是支援團隊成員。",
"member":"您需要是成員。",
"discord-administrator":"您需要擁有`ADMINISTRATOR`權限。"
},
"actionInvalid":{
"close":"工單已關閉!",
"reopen":"工單未關閉!",
"claim":"工單已認領!",
"unclaim":"工單未認領!",
"pin":"工單已置頂!",
"unpin":"工單未置頂!",
"add":"此用戶已可訪問工單!",
"remove":"無法從此工單移除此用戶!"
}
},
"params":{
"uppercase":{
"ticket":"工單",
"tickets":"工單",
"reason":"原因",
"creator":"創建者",
"remaining":"剩餘時間",
"added":"已添加",
"removed":"已移除",
"filter":"篩選",
"method":"方式",
"type":"類型",
"blacklisted":"已拉黑",
"panel":"麵闆",
"command":"命令",
"system":"係統",
"true":"是",
"false":"否",
"syntax":"文法",
"originalName":"原名稱",
"newName":"新名稱",
"until":"直到",
"validOptions":"有效選項",
"validPanels":"有效麵闆",
"autoclose":"自動關閉",
"autodelete":"自動刪除",
"startupDate":"啟動日期",
"version":"版本",
"name":"名稱",
"role":"角色",
"status":"狀態",
"claimed":"已認領",
"pinned":"已置頂",
"creationDate":"創建日期",
"noone":"無人",
"open":"開啟",
"closed":"關閉",
"priority":"優先級",
"participants":"參與者",
"yes":"是",
"no":"否",
"option":"選項",
"topic":"主題",
"uptime":"係統運行時間",
"messages":"消息",
"embeds":"嵌入",
"files":"文件",
"components":"組件",
"cooldown":"冷卻時間",
"maxTickets":"最大工單數",
"admins":"管理員",
"roles":"角色",
"size":"大小"
},
"lowercase":{
"text":"文本",
"html":"HTML",
"command":"命令",
"modal":"模態框",
"button":"按鈕",
"dropdown":"下拉菜單",
"method":"方式"
}
},
"commands":{
"reason":"指定一個可選原因,該原因將在日誌中可見。",
"help":"獲取所有可用命令的列錶。",
"panel":"生成帶有下拉菜單或按鈕的消息(用於工單創建)。",
"panelId":"您想要生成的麵闆的標識符。",
"panelAutoUpdate":"您希望此麵闆在編輯時自動更新嗎?",
"ticket":"立即創建一個工單。",
"ticketId":"您想要創建的工單的標識符。",
"close":"關閉一個工單。",
"delete":"刪除一個工單。",
"deleteNoTranscript":"刪除此工單而不創建記錄。",
"reopen":"重新開啟一個工單。",
"claim":"認領一個工單。",
"claimUser":"將此工單認領給其他人而不是您自己。",
"unclaim":"取消認領一個工單。",
"pin":"置頂一個工單。",
"unpin":"取消置頂一個工單。",
"move":"移動一個工單。",
"moveId":"您想要移動到的選項的標識符。",
"rename":"重命名一個工單。",
"renameName":"此工單的新名稱。",
"add":"將用戶添加到工單。",
"addUser":"要添加的用戶。",
"remove":"從工單中移除用戶。",
"removeUser":"要移除的用戶。",
"blacklist":"管理工單黑名單。",
"blacklistView":"檢視當前黑名單的列錶。",
"blacklistAdd":"將用戶添加到黑名單。",
"blacklistRemove":"從黑名單中移除用戶。",
"blacklistGet":"獲取被拉黑用戶的詳細信息。",
"blacklistGetUser":"要獲取詳細信息的用戶。",
"stats":"檢視機器人、成員或工單的統計信息。",
"statsReset":"重置機器人的所有統計信息(並從零開始計數)。",
"statsGlobal":"檢視全局統計信息。",
"statsUser":"檢視服務器中用戶的統計信息。",
"statsUserUser":"要檢視的用戶。",
"statsTicket":"檢視服務器中工單的統計信息。",
"statsTicketTicket":"要檢視的工單。",
"clear":"同時刪除多個工單。",
"clearFilter":"清除工單的篩選條件。",
"clearFilters":{
"all":"全部",
"open":"開啟",
"close":"關閉",
"claim":"已認領",
"unclaim":"未認領",
"pin":"已置頂",
"unpin":"未置頂",
"autoclose":"自動關閉"
},
"autoclose":"管理工單中的自動關閉。",
"autocloseDisable":"禁用此工單的自動關閉。",
"autocloseEnable":"啟用此工單的自動關閉。",
"autocloseEnableTime":"工單需要多少小時不活動才能自動關閉。",
"autodelete":"管理工單中的自動刪除。",
"autodeleteDisable":"禁用此工單的自動刪除。",
"autodeleteEnable":"啟用此工單的自動刪除。",
"autodeleteEnableTime":"工單需要多少天不活動才能自動刪除。",
"topic":"管理工單頻道的主題。",
"topicSet":"設定工單頻道的主題。",
"topicValue":"頻道的新主題。",
"topicList":"獲取所有工單及其主題和統計信息的列錶。",
"priority":"管理工單的優先級。",
"prioritySet":"設定工單的優先級。",
"priorityValue":"頻道的優先級。",
"priorityGet":"獲取工單的優先級。",
"priorityList":"獲取所有工單的優先級狀態列錶。",
"transfer":"將工單所有權從一位用戶轉移至另一位用戶。",
"transferUser":"要轉移給的用戶。"
},
"helpMenu":{
"help":"獲取所有可用命令的列錶。",
"ticket":"立即創建一個工單。",
"close":"關閉一個工單,這將禁用此頻道的寫入權限。",
"delete":"刪除一個工單,啟用時會創建記錄。",
"reopen":"重新開啟一個工單,這將重新啟用此頻道的寫入權限。",
"pin":"置頂一個工單。這將把工單移動到頂部,並在名稱前添加'📌'錶情符號。",
"unpin":"取消置頂一個工單。工單將保持當前位置,但會移除'📌'錶情符號。",
"move":"移動一個工單。這將更改此工單的類型。",
"rename":"重命名一個工單。這將更改此工單的頻道名稱。",
"claim":"認領一個工單。通過此操作,您可以告知團隊您正在處理此工單。",
"unclaim":"取消認領一個工單。通過此操作,您可以告知團隊此工單已空閒。",
"add":"將用戶添加到工單。這將允許用戶在此工單中讀取和寫入。",
"remove":"從工單中移除用戶。這將移除用戶在此工單中讀取和寫入的權限。",
"panel":"生成帶有下拉菜單或按鈕的消息(用於工單創建)。",
"blacklistView":"檢視當前黑名單的列錶。",
"blacklistAdd":"將用戶添加到黑名單。",
"blacklistRemove":"從黑名單中移除用戶。",
"blacklistGet":"獲取被拉黑用戶的詳細信息。",
"statsGlobal":"檢視全局統計信息。",
"statsTicket":"檢視服務器中工單的統計信息。",
"statsUser":"檢視服務器中用戶的統計信息。",
"statsReset":"重置機器人的所有統計信息(並從零開始計數)。",
"autocloseDisable":"禁用此工單的自動關閉。",
"autocloseEnable":"啟用此工單的自動關閉。",
"autodeleteDisable":"禁用此工單的自動刪除。",
"autodeleteEnable":"啟用此工單的自動刪除。",
"categories":{
"general":"通用命令",
"basicTicket":"基礎工單命令",
"advancedTicket":"高級工單命令",
"userTicket":"用戶工單命令",
"admin":"管理員命令",
"advanced":"高級命令",
"extra":"額外命令"
}
},
"stats":{
"scopes":{
"global":"全局統計",
"system":"係統統計",
"user":"用戶統計",
"ticket":"工單統計",
"participants":"參與者",
"messages":"消息"
},
"properties":{
"ticketsCreated":"工單已創建",
"ticketsClosed":"工單已關閉",
"ticketsDeleted":"工單已刪除",
"ticketsReopened":"工單已重新開啟",
"ticketsAutoclosed":"工單已自動關閉",
"ticketsClaimed":"工單已認領",
"ticketsPinned":"工單已置頂",
"ticketsMoved":"工單已移動",
"usersBlacklisted":"用戶已拉黑",
"transcriptsCreated":"記錄已創建",
"ticketsAutodeleted":"自動刪除的工單",
"ticketsTransferred":"已轉移的工單",
"ticketVolume":"工單量",
"averageTickets":"平均工單數/用戶",
"currentTickets":"當前工單",
"age":"工單時長",
"responseTime":"回響時間",
"resolutionTime":"解決時間",
"createdOn":"創建於",
"createdBy":"創建者",
"closedOn":"關閉於",
"closedBy":"關閉者",
"claimedOn":"認領於",
"claimedBy":"認領者",
"pinnedOn":"固定於",
"pinnedBy":"固定者",
"deletedOn":"刪除於",
"deletedBy":"刪除者"
},
"roles":{
"developer":"開發者",
"serverOwner":"服務器所有者",
"serverAdmin":"服務器管理員",
"moderator":"管理團隊",
"support":"支援團隊",
"member":"成員"
}
},
"panel":{
"selectTicket":"選擇您的工單",
"selectRole":"選擇您的角色",
"selectOption":"選擇您的選項"
},
"priorities":{
"urgent":"緊急",
"veryHigh":"非常高",
"high":"高",
"normal":"普通",
"low":"低",
"veryLow":"非常低",
"none":"無"
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["palestinian"], "translators":["palestinian"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Turkish", "language":"Turkish",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["Anderskiy"], "translators":["Anderskiy"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Ukrainian", "language":"Ukrainian",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"_TRANSLATION":{ "_TRANSLATION":{
"otversion":"v4.1.3", "otversion":"v4.2.0",
"translators":["ngocdiep2006"], "translators":["ngocdiep2006"],
"lastedited":"16/02/2026", "lastedited":"16/02/2026",
"language":"Vietnamese", "language":"Vietnamese",
+10 -9
View File
@@ -1,7 +1,7 @@
{ {
"name": "open-ticket", "name": "open-ticket",
"author": "DJdj Development", "author": "DJdj Development",
"version": "4.1.3", "version": "4.2.0",
"description": "The most advanced open-source discord ticket bot with HTML transcripts, plugins, questions, claiming, pinning & more! Using discord.js v14 & JSON database! ", "description": "The most advanced open-source discord ticket bot with HTML transcripts, plugins, questions, claiming, pinning & more! Using discord.js v14 & JSON database! ",
"keywords": [ "keywords": [
"ticket-bot", "ticket-bot",
@@ -19,20 +19,21 @@
"test": "node index.js --dev-config --dev-database --soft-plugins", "test": "node index.js --dev-config --dev-database --soft-plugins",
"testsetup": "node index.js --cli --dev-config --dev-database --soft-plugins", "testsetup": "node index.js --cli --dev-config --dev-database --soft-plugins",
"testnc": "node index.js --no-compile --dev-config --dev-database --soft-plugins", "testnc": "node index.js --no-compile --dev-config --dev-database --soft-plugins",
"docs": "npx typedoc --options .docs/typedoc-config.json && node .docs/createDocs.js", "docs": "npx typedoc --options .tools/typedoc-config.json && node .tools/createDocs.js",
"mergelang": "node .docs/mergeTranslations.js" "mergelang": "node .tools/mergeTranslations.js"
}, },
"type": "commonjs", "type": "module",
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"dependencies": { "dependencies": {
"@discordjs/rest": "^2.6.0", "@discordjs/rest": "^2.6.1",
"@open-discord-bots/framework": "^0.4.4",
"@types/node": "^22.5.0", "@types/node": "^22.5.0",
"@types/terminal-kit": "^2.5.7", "@types/terminal-kit": "^2.5.7",
"ansis": "^4.2.0", "ansis": "^4.2.0",
"discord.js": "^14.24.2", "discord.js": "^14.26.4",
"formatted-json-stringify": "^1.2.1", "formatted-json-stringify": "^1.3.2",
"terminal-kit": "^3.1.2", "terminal-kit": "^3.1.2",
"typescript": "^5.9.3" "typescript": "^6.0.3"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -45,7 +46,7 @@
"homepage": "https://openticket.dj-dj.be", "homepage": "https://openticket.dj-dj.be",
"imports": { "imports": {
"#opendiscord": "./dist/src/index.js", "#opendiscord": "./dist/src/index.js",
"#opendiscord-types": "./dist/src/core/api/api.js" "#opendiscord-types": "./dist/src/core/api.js"
}, },
"funding": { "funding": {
"type": "individual", "type": "individual",
+5 -5
View File
@@ -6,15 +6,15 @@ import * as discord from "discord.js"
//// Enable it in the plugin.json file! //// //// Enable it in the plugin.json file! ////
///////////////////////////////////////////// /////////////////////////////////////////////
if (utilities.project != "openticket") throw new api.ODPluginError("This plugin only works in Open Ticket!") if (opendiscord.project != "openticket") throw new api.ODPluginError("This plugin only works in Open Ticket!")
//Add Typescript autocomplete support for plugin data. (!!!OPTIONAL!!!) //Add Typescript autocomplete support for plugin data. (!!!OPTIONAL!!!)
declare module "#opendiscord-types" { declare module "#opendiscord-types" {
export interface ODPluginManagerIds_Default { export interface ODPluginManagerIdMappings {
"example-plugin":api.ODPlugin "example-plugin":api.ODPlugin
} }
export interface ODConfigManagerIds_Default { export interface ODConfigManagerIdMappings {
"example-plugin:config":api.ODJsonConfig "example-plugin:config":api.ODJsonConfig<{testVariable1:boolean,testVariable2:number,testVariable3:string}>
} }
} }
@@ -30,7 +30,7 @@ opendiscord.events.get("onConfigLoad").listen((configManager) => {
//Let's also log it to the console to let us know it worked! //Let's also log it to the console to let us know it worked!
const ourConfig = configManager.get("example-plugin:config") const ourConfig = configManager.get("example-plugin:config")
opendiscord.log("The example config loaded successfully!","plugin",[ opendiscord.log("The example config loaded successfully!","plugin",[
{key:"var-1",value:ourConfig.data.testVariable1}, {key:"var-1",value:ourConfig.data.testVariable1.toString()},
{key:"var-2",value:ourConfig.data.testVariable2.toString()}, {key:"var-2",value:ourConfig.data.testVariable2.toString()},
{key:"var-3",value:ourConfig.data.testVariable3.toString()} {key:"var-3",value:ourConfig.data.testVariable3.toString()}
]) ])
+12 -25
View File
@@ -1,15 +1,15 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET ADD USER SYSTEM //TICKET ADD USER SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:add-ticket-user")) opendiscord.actions.add(new api.ODAction("opendiscord:add-ticket-user"))
opendiscord.actions.get("opendiscord:add-ticket-user").workers.add([ opendiscord.actions.get("opendiscord:add-ticket-user").workers.add([
new api.ODWorker("opendiscord:add-ticket-user",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:add-ticket-user",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params const {guild,channel,user,ticket,reason,data} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to add user to ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to add user to ticket! Open Ticket doesn't support threads!")
@@ -34,44 +34,31 @@ export const registerActions = async () => {
opendiscord.log("Failed to add channel permission overwrites on add-ticket-user","error") opendiscord.log("Failed to add channel permission overwrites on add-ticket-user","error")
} }
//update ticket message //update ticket message (no await)
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket) openticketUtils.updateTicketMessage(guild,channel,user,ticket)
if (ticketMessage){
try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
}catch(e){
opendiscord.log("Unable to edit ticket message on ticket user adding!","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"messageid",value:ticketMessage.id},
{key:"option",value:ticket.option.id.value,hidden:true}
])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:add-message").build(source,{guild,channel,user,ticket,reason,data})).message) if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:add-message").build(origin,{guild,channel,user,ticket,reason,data})).message)
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketUserAdded").emit([ticket,user,data,channel,reason]) await opendiscord.events.get("afterTicketUserAdded").emit([ticket,user,data,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params const {guild,channel,user,ticket,reason,data} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.adding.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.adding.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"add",reason,additionalData:data})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"add",reason,additionalData:data}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.adding.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"add",reason,additionalData:data})) if (creator && generalConfig.data.logs.logMessages.adding.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"add",reason,additionalData:data}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,data} = params const {guild,channel,user,ticket,data} = params
opendiscord.log(user.displayName+" added "+data.displayName+" to a ticket!","info",[ opendiscord.log(user.displayName+" added "+data.displayName+" to a ticket!","info",[
@@ -80,7 +67,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
+129
View File
@@ -0,0 +1,129 @@
///////////////////////////////////////
//CALCULATE TICKET CATEGORY SYSTEM
///////////////////////////////////////
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:calculate-ticket-category"))
opendiscord.actions.get("opendiscord:calculate-ticket-category").workers.add([
new api.ODWorker("opendiscord:default-category",2,async (instance,params,origin,cancel) => {
//handle default category
const {guild,user,channel,option,ticket,currentCategoryId} = params
const defaultCategoryId = option.get("opendiscord:channel-category").value
if (!defaultCategoryId){
//default category is disabled
instance.newCategoryId = null
instance.newCategoryMode = null
instance.newCategory = null
instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
}else{
const defaultCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,defaultCategoryId)
if (defaultCategory){
//default category is enabled
instance.newCategoryId = defaultCategoryId
instance.newCategoryMode = "default"
instance.newCategory = defaultCategory
instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
}else{
//default category is not found (do not switch categories)
opendiscord.log("Unable to find ticket category '"+defaultCategoryId+"' #1","error",[
{key:"categoryid",value:defaultCategoryId},
{key:"type",value:"default"}
])
instance.newCategoryId = null
instance.newCategoryMode = null
instance.newCategory = null
instance.shouldChangeCategory = false
}
}
}),
new api.ODWorker("opendiscord:close-category",1,async (instance,params,origin,cancel) => {
//handle close category
const {guild,user,channel,option,ticket,currentCategoryId} = params
if (!ticket) return
if (!ticket.get("opendiscord:closed").value) return
if (!generalConfig.data.ticketSystem.closedCategory.enabled) return
const closeCategoryId = generalConfig.data.ticketSystem.closedCategory.categoryId
if (!closeCategoryId) return
const closeCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,closeCategoryId)
if (closeCategory){
//close category is enabled
instance.newCategoryId = closeCategoryId
instance.newCategoryMode = "close"
instance.newCategory = closeCategory
instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
}else{
//close category is not found (do not switch categories)
opendiscord.log("Unable to find ticket category '"+closeCategoryId+"' #2","error",[
{key:"categoryid",value:closeCategoryId},
{key:"type",value:"close"}
])
instance.newCategoryId = null
instance.newCategoryMode = null
instance.newCategory = null
instance.shouldChangeCategory = false
}
}),
new api.ODWorker("opendiscord:claim-category",0,async (instance,params,origin,cancel) => {
//handle claim category
const {guild,user,channel,option,ticket,currentCategoryId} = params
if (!ticket) return
if (!ticket.get("opendiscord:claimed").value) return
const claimedCategoryIds = generalConfig.data.ticketSystem.claimedCategories
const claimCategoryId = claimedCategoryIds.find((c) => c.user == user.id)?.category
if (!claimCategoryId) return
const claimCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,claimCategoryId)
if (claimCategory){
//claim category is enabled
instance.newCategoryId = claimCategoryId
instance.newCategoryMode = "claim"
instance.newCategory = claimCategory
instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
}else{
//claim category is not found (do not switch categories)
opendiscord.log("Unable to find ticket category '"+claimCategoryId+"' #3","error",[
{key:"categoryid",value:claimCategoryId},
{key:"type",value:"claim"}
])
instance.newCategoryId = null
instance.newCategoryMode = null
instance.newCategory = null
instance.shouldChangeCategory = false
}
}),
new api.ODWorker("opendiscord:backup-category",-100,async (instance,params,origin,cancel) => {
//handle backup category
const {guild,user,channel,option,ticket,currentCategoryId} = params
if (!instance.newCategory || !instance.newCategoryId || !instance.shouldChangeCategory) return
if (instance.newCategory.children.cache.size < 50) return
if (!generalConfig.data.ticketSystem.backupCategory.enabled) return
const backupCategoryId = generalConfig.data.ticketSystem.backupCategory.categoryId
if (!backupCategoryId) return
const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,backupCategoryId)
if (backupCategory){
//backup category is enabled
instance.newCategoryId = backupCategoryId
instance.newCategoryMode = "backup"
instance.newCategory = backupCategory
instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
}else{
//backup category is not found (do not switch categories)
opendiscord.log("Unable to find ticket category '"+backupCategoryId+"' #4","error",[
{key:"categoryid",value:backupCategoryId},
{key:"type",value:"backup"}
])
instance.newCategoryId = null
instance.newCategoryMode = null
instance.newCategory = null
instance.shouldChangeCategory = false
}
})
])
}
+30
View File
@@ -0,0 +1,30 @@
///////////////////////////////////////
//CALCULATE TICKET NAME SYSTEM
///////////////////////////////////////
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:calculate-ticket-name"))
opendiscord.actions.get("opendiscord:calculate-ticket-name").workers.add([
new api.ODWorker("opendiscord:calculate-ticket-name",0,async (instance,params,origin,cancel) => {
const {guild,user,channel,option,ticket,currentChannelName} = params
//calculate base channel name
const channelPrefix = option.get("opendiscord:channel-prefix").value
const channelSuffix = (ticket) ? ticket.get("opendiscord:channel-suffix").value : (await opendiscord.options.suffix.getSuffixFromOption(option,user,guild) ?? "unknown")
const channelRenamed = (ticket && ticket.exists("opendiscord:channel-renamed")) ? ticket.get("opendiscord:channel-renamed").value : null
const baseChannelName = (channelRenamed) ? channelRenamed : channelPrefix+channelSuffix
//calculate status emojis
const pinEmoji = (ticket && ticket.get("opendiscord:pinned").value) ? generalConfig.data.ticketSystem.pinEmoji : ""
const priorityEmoji = (ticket) ? (opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? "") : ""
instance.newChannelName = pinEmoji+priorityEmoji+baseChannelName
instance.newChannelSuffix = channelSuffix
instance.shouldChangeName = (instance.newChannelName !== currentChannelName)
})
])
}
+39 -219
View File
@@ -1,15 +1,16 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET CLAIMING SYSTEM //TICKET CLAIMING SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:claim-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:claim-ticket"))
opendiscord.actions.get("opendiscord:claim-ticket").workers.add([ opendiscord.actions.get("opendiscord:claim-ticket").workers.add([
new api.ODWorker("opendiscord:claim-ticket",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:claim-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to claim ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to claim ticket! Open Ticket doesn't support threads!")
@@ -22,67 +23,66 @@ export const registerActions = async () => {
ticket.get("opendiscord:busy").value = true ticket.get("opendiscord:busy").value = true
//update stats //update stats
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-claimed",1,"increase") await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-claimed",1,"increase")
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-claimed",user.id,1,"increase") await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-claimed",user.id,1,"increase")
//update category //calculate & update category
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){ if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
const rawClaimCategory = ticket.option.get("opendiscord:channel-categories-claimed").value.find((c) => c.user == user.id) const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("claim-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
const claimCategory = (rawClaimCategory) ? rawClaimCategory.category : null if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
if (claimCategory){ const originalCategoryName = channel.parent?.name ?? "<unknown>"
try { const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
channel.setParent(claimCategory,{lockPermissions:false}) try{
ticket.get("opendiscord:category-mode").value = "claimed" await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
ticket.get("opendiscord:category").value = claimCategory process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
}catch(e){ })
opendiscord.log("Unable to move ticket to 'claimed category'!","error",[ ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
ticket.get("opendiscord:category").value = categoryResult.newCategoryId
}catch(err){
const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-claim",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
opendiscord.log("Unable to move ticket to claimed category.","error",[
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"categoryid",value:claimCategory} {key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
]) ])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
} }
} }
} }
//update ticket message //update ticket message (no await)
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket) openticketUtils.updateTicketMessage(guild,channel,user,ticket)
if (ticketMessage){
try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
}catch(e){
opendiscord.log("Unable to edit ticket message on ticket claiming!","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"messageid",value:ticketMessage.id},
{key:"option",value:ticket.option.id.value}
])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(source,{guild,channel,user,ticket,reason})).message) if (params.sendMessage){
const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(origin,{guild,channel,user,ticket,reason})).message)
if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
messageType:"claim-message",
messageOrigin:"other",
messageAuthor:user.id,
messageReason:reason
},false)
}
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketClaimed").emit([ticket,user,channel,reason]) await opendiscord.events.get("afterTicketClaimed").emit([ticket,user,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.claiming.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.claiming.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"claim",reason,additionalData:null})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"claim",reason,additionalData:null}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.claiming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"claim",reason,additionalData:null})) if (creator && generalConfig.data.logs.logMessages.claiming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"claim",reason,additionalData:null}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" claimed a ticket!","info",[ opendiscord.log(user.displayName+" claimed a ticket!","info",[
@@ -91,7 +91,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
@@ -100,183 +100,3 @@ export const registerActions = async () => {
params.ticket.get("opendiscord:busy").value = false params.ticket.get("opendiscord:busy").value = false
}) })
} }
export const registerVerifyBars = async () => {
//CLAIM TICKET TICKET MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:claim-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:claim-ticket-ticket-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.claim
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when already claimed
if (ticket.get("opendiscord:claimed").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start claiming ticket
if (params.data == "reason"){
//claim with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:claim-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
}else{
//claim without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:claim-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
}
})
])
opendiscord.verifybars.get("opendiscord:claim-ticket-ticket-message").failure.add([
new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
})
])
//CLAIM TICKET UNCLAIM MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:claim-ticket-unclaim-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-unclaim-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:claim-ticket-unclaim-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.claim
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when already claimed
if (ticket.get("opendiscord:claimed").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start claiming ticket
if (params.data == "reason"){
//claim with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:claim-ticket-reason").build("unclaim-message",{guild,channel,user,ticket}))
}else{
//claim without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:claim-ticket").run("unclaim-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("unclaim-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:claim-ticket-unclaim-message").failure.add([
new api.ODWorker("opendiscord:back-to-unclaim-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("other",{guild,channel,user,ticket,reason}))
})
])
}
+8 -8
View File
@@ -1,15 +1,15 @@
/////////////////////////////////////// ///////////////////////////////////////
//CLEAR TICKETS SYSTEM //CLEAR TICKETS SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:clear-tickets")) opendiscord.actions.add(new api.ODAction("opendiscord:clear-tickets"))
opendiscord.actions.get("opendiscord:clear-tickets").workers.add([ opendiscord.actions.get("opendiscord:clear-tickets").workers.add([
new api.ODWorker("opendiscord:clear-tickets",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:clear-tickets",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,filter,list} = params const {guild,channel,user,filter,list} = params
await opendiscord.events.get("onTicketsClear").emit([list,user,channel,filter]) await opendiscord.events.get("onTicketsClear").emit([list,user,channel,filter])
@@ -43,21 +43,21 @@ export const registerActions = async () => {
instance.list = nameList instance.list = nameList
await opendiscord.events.get("afterTicketsCleared").emit([list,user,channel,filter]) await opendiscord.events.get("afterTicketsCleared").emit([list,user,channel,filter])
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,filter,list} = params const {guild,channel,user,filter,list} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.deleting.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.deleting.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:clear-logs").build(source,{guild,channel,user,filter,list:instance.list ?? []})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:clear-logs").build(origin,{guild,channel,user,filter,list:instance.list ?? []}))
} }
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,user,filter,list} = params const {guild,user,filter,list} = params
opendiscord.log(user.displayName+" cleared "+list.length+" tickets!","info",[ opendiscord.log(user.displayName+" cleared "+list.length+" tickets!","info",[
{key:"user",value:user.username}, {key:"user",value:user.username},
{key:"userid",value:user.id,hidden:true}, {key:"userid",value:user.id,hidden:true},
{key:"method",value:source}, {key:"method",value:origin},
{key:"filter",value:filter} {key:"filter",value:filter}
]) ])
}) })
+41 -208
View File
@@ -1,16 +1,17 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET CLOSING SYSTEM //TICKET CLOSING SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages const lang = opendiscord.languages
const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:close-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:close-ticket"))
opendiscord.actions.get("opendiscord:close-ticket").workers.add([ opendiscord.actions.get("opendiscord:close-ticket").workers.add([
new api.ODWorker("opendiscord:close-ticket",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:close-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to close ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to close ticket! Open Ticket doesn't support threads!")
@@ -25,29 +26,34 @@ export const registerActions = async () => {
ticket.get("opendiscord:reopened-by").value = null ticket.get("opendiscord:reopened-by").value = null
ticket.get("opendiscord:reopened-on").value = null ticket.get("opendiscord:reopened-on").value = null
if (source == "autoclose") ticket.get("opendiscord:autoclosed").value = true if (origin == "autoclose") ticket.get("opendiscord:autoclosed").value = true
ticket.get("opendiscord:open").value = false ticket.get("opendiscord:open").value = false
ticket.get("opendiscord:busy").value = true ticket.get("opendiscord:busy").value = true
//update stats //update stats
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-closed",1,"increase") await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-closed",1,"increase")
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-closed",user.id,1,"increase") await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-closed",user.id,1,"increase")
//update category //calculate & update category
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){ if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
const closeCategory = ticket.option.get("opendiscord:channel-category-closed").value const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("close-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
if (closeCategory !== ""){ if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
try { const originalCategoryName = channel.parent?.name ?? "<unknown>"
channel.setParent(closeCategory,{lockPermissions:false}) const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
ticket.get("opendiscord:category-mode").value = "closed" try{
ticket.get("opendiscord:category").value = closeCategory await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
}catch(e){ process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
opendiscord.log("Unable to move ticket to 'closed category'!","error",[ })
ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
ticket.get("opendiscord:category").value = categoryResult.newCategoryId
}catch(err){
const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-close",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
opendiscord.log("Unable to move ticket to closed category.","error",[
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"categoryid",value:closeCategory} {key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
]) ])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
} }
} }
} }
@@ -93,7 +99,7 @@ export const registerActions = async () => {
ticket.get("opendiscord:participants").value.forEach((participant) => { ticket.get("opendiscord:participants").value.forEach((participant) => {
//all participants that aren't roles/admins => readonly (OR non-viewable when enabled) //all participants that aren't roles/admins => readonly (OR non-viewable when enabled)
if (participant.type == "user"){ if (participant.type == "user"){
if (generalConfig.data.system.removeParticipantsOnClose) permissions.push({ if (generalConfig.data.ticketSystem.removeParticipantsOnClose) permissions.push({
type:discord.OverwriteType.Member, type:discord.OverwriteType.Member,
id:participant.id, id:participant.id,
allow:[], allow:[],
@@ -109,44 +115,39 @@ export const registerActions = async () => {
}) })
channel.permissionOverwrites.set(permissions) channel.permissionOverwrites.set(permissions)
//update ticket message //update ticket message (no await)
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket) openticketUtils.updateTicketMessage(guild,channel,user,ticket)
if (ticketMessage){
try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
}catch(e){
opendiscord.log("Unable to edit ticket message on ticket closing!","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"messageid",value:ticketMessage.id},
{key:"option",value:ticket.option.id.value}
])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(source,{guild,channel,user,ticket,reason})).message) if (params.sendMessage){
const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(origin,{guild,channel,user,ticket,reason})).message)
if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
messageType:"close-message",
messageOrigin:"other",
messageAuthor:user.id,
messageReason:reason
},false)
}
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketClosed").emit([ticket,user,channel,reason]) await opendiscord.events.get("afterTicketClosed").emit([ticket,user,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.closing.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.closing.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"close",reason,additionalData:null})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"close",reason,additionalData:null}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.closing.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"close",reason,additionalData:null})) if (creator && generalConfig.data.logs.logMessages.closing.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"close",reason,additionalData:null}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" closed a ticket!","info",[ opendiscord.log(user.displayName+" closed a ticket!","info",[
@@ -155,7 +156,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
@@ -164,171 +165,3 @@ export const registerActions = async () => {
params.ticket.get("opendiscord:busy").value = false params.ticket.get("opendiscord:busy").value = false
}) })
} }
export const registerVerifyBars = async () => {
//CLOSE TICKET TICKET MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:close-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:close-ticket-ticket-message").success.add([
new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,source,cancel) => {
const {user,member,channel,guild} = instance
//check permissions
const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.close,"support",user,member,channel,guild)
if (!permsResult.hasPerms){
if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
return cancel()
}
//check is in guild/server
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
//check if ticket exists
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when already closed
if (ticket.get("opendiscord:closed").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:lang.getTranslation("errors.actionInvalid.close"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//return when not allowed because of missing messages
if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
}
//start closing ticket
if (params.data == "reason"){
//close with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:close-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
}else{
//close without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:close-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
}
})
])
opendiscord.verifybars.get("opendiscord:close-ticket-ticket-message").failure.add([
new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
})
])
//CLOSE TICKET REOPEN MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:close-ticket-reopen-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-reopen-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:close-ticket-reopen-message").success.add([
new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,source,cancel) => {
const {user,member,channel,guild} = instance
//check permissions
const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.close,"support",user,member,channel,guild)
if (!permsResult.hasPerms){
if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
return cancel()
}
//check is in guild/server
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
//check if ticket exists
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when already closed
if (ticket.get("opendiscord:closed").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:lang.getTranslation("errors.actionInvalid.close"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//return when not allowed because of missing messages
if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
}
//start closing ticket
if (params.data == "reason"){
//close with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:close-ticket-reason").build("reopen-message",{guild,channel,user,ticket}))
}else{
//close without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:close-ticket").run("reopen-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("reopen-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:close-ticket-reopen-message").failure.add([
new api.ODWorker("opendiscord:back-to-reopen-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason}))
})
])
}
+50 -68
View File
@@ -1,63 +1,36 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET CREATION SYSTEM //TICKET CREATION SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages const lang = opendiscord.languages
const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:create-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:create-ticket"))
opendiscord.actions.get("opendiscord:create-ticket").workers.add([ opendiscord.actions.get("opendiscord:create-ticket").workers.add([
new api.ODWorker("opendiscord:create-ticket",3,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:create-ticket",3,async (instance,params,origin,cancel) => {
const {guild,user,answers,option} = params const {guild,user,answers,option} = params
await opendiscord.events.get("onTicketCreate").emit([user]) await opendiscord.events.get("onTicketCreate").emit([user])
await opendiscord.events.get("onTicketChannelCreation").emit([option,user]) await opendiscord.events.get("onTicketChannelCreation").emit([option,user])
//get channel properties //get channel properties
const channelPrefix = option.get("opendiscord:channel-prefix").value
const channelCategory = option.get("opendiscord:channel-category").value
const channelBackupCategory = option.get("opendiscord:channel-category-backup").value
const channelTopicText = option.get("opendiscord:channel-topic").value const channelTopicText = option.get("opendiscord:channel-topic").value
const channelSuffix = await opendiscord.options.suffix.getSuffixFromOption(option,user,guild)
const channelName = channelPrefix+channelSuffix
//handle category //calculate channel name
let category: string|null = null const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("create-ticket",{guild,user,option,channel:null,ticket:null,currentChannelName:null})
let categoryMode: "backup"|"normal"|null = null if (!channelNameResult) return opendiscord.log("Ticket Creation Error: Unable to calculate ticket name.","error")
if (channelCategory != ""){ const channelName = (channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined") ? channelNameResult.newChannelName : "ot-unnamed-ticket"
//category enabled const channelSuffix = (typeof channelNameResult.newChannelSuffix !== "undefined") ? channelNameResult.newChannelSuffix : "unknown"
const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory)
if (!normalCategory){ //calculate category
//default category was not found const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("create-ticket",{guild,user,option,channel:null,ticket:null,currentCategoryId:null})
opendiscord.log("Ticket Creation Error: Unable to find category! #1","error",[ if (!categoryResult) return opendiscord.log("Ticket Creation Error: Unable to calculate ticket category.","error")
{key:"categoryid",value:channelCategory}, const ticketCategoryId = (categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined") ? categoryResult.newCategoryId : undefined
{key:"backup",value:"false"} const ticketCategoryMode = (categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryMode !== "undefined") ? categoryResult.newCategoryMode : undefined
])
}else{
//default category was found
if (normalCategory.children.cache.size >= 50 && channelBackupCategory != ""){
//use backup category
const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelBackupCategory)
if (!backupCategory){
//default category was not found
opendiscord.log("Ticket Creation Error: Unable to find category! #2","error",[
{key:"categoryid",value:channelBackupCategory},
{key:"backup",value:"true"}
])
}else{
category = backupCategory.id
categoryMode = "backup"
}
}else{
//use default category
category = normalCategory.id
categoryMode = "normal"
}
}
}
//handle permissions //handle permissions
const permissions: discord.OverwriteResolvable[] = [{ const permissions: discord.OverwriteResolvable[] = [{
@@ -118,15 +91,15 @@ export const registerActions = async () => {
//handle channel topic //handle channel topic
const channelTopics: string[] = [] const channelTopics: string[] = []
if (generalConfig.data.system.channelTopic.showOptionName) channelTopics.push(option.get("opendiscord:name").value) if (generalConfig.data.ticketSystem.channelTopic.showOptionName) channelTopics.push(option.get("opendiscord:name").value)
if (generalConfig.data.system.channelTopic.showOptionDescription) channelTopics.push(option.get("opendiscord:description").value) if (generalConfig.data.ticketSystem.channelTopic.showOptionDescription) channelTopics.push(option.get("opendiscord:description").value)
if (generalConfig.data.system.channelTopic.showOptionTopic) channelTopics.push(channelTopicText) if (generalConfig.data.ticketSystem.channelTopic.showOptionTopic) channelTopics.push(channelTopicText)
if (generalConfig.data.system.channelTopic.showPriority) channelTopics.push("**"+lang.getTranslation("params.uppercase.priority")+":** "+opendiscord.priorities.get("opendiscord:none").renderDisplayName()) if (generalConfig.data.ticketSystem.channelTopic.showPriority) channelTopics.push("**"+lang.getTranslation("params.uppercase.priority")+":** "+opendiscord.priorities.get("opendiscord:none").renderDisplayName())
if (generalConfig.data.system.channelTopic.showClosed) channelTopics.push("**"+lang.getTranslation("params.uppercase.status")+":** "+lang.getTranslation("params.uppercase.open")) if (generalConfig.data.ticketSystem.channelTopic.showClosed) channelTopics.push("**"+lang.getTranslation("params.uppercase.status")+":** "+lang.getTranslation("params.uppercase.open"))
if (generalConfig.data.system.channelTopic.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+lang.getTranslation("params.uppercase.noone")) if (generalConfig.data.ticketSystem.channelTopic.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+lang.getTranslation("params.uppercase.noone"))
if (generalConfig.data.system.channelTopic.showPinned) channelTopics.push("**"+lang.getTranslation("params.uppercase.pinned")+":** "+lang.getTranslation("params.uppercase.no")) if (generalConfig.data.ticketSystem.channelTopic.showPinned) channelTopics.push("**"+lang.getTranslation("params.uppercase.pinned")+":** "+lang.getTranslation("params.uppercase.no"))
if (generalConfig.data.system.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(user.id)) if (generalConfig.data.ticketSystem.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(user.id))
if (generalConfig.data.system.channelTopic.showParticipants) channelTopics.push("**"+lang.getTranslation("params.uppercase.participants")+":** "+participants.map((p) => (p.type == "user") ? discord.userMention(p.id) : discord.roleMention(p.id)).join(", ")) if (generalConfig.data.ticketSystem.channelTopic.showParticipants) channelTopics.push("**"+lang.getTranslation("params.uppercase.participants")+":** "+participants.map((p) => (p.type == "user") ? discord.userMention(p.id) : discord.roleMention(p.id)).join(", "))
//create channel //create channel
const channel = await guild.channels.create({ const channel = await guild.channels.create({
@@ -134,7 +107,7 @@ export const registerActions = async () => {
name:channelName, name:channelName,
nsfw:false, nsfw:false,
topic:(channelTopics.length > 0) ? channelTopics.join(" • ") : undefined, topic:(channelTopics.length > 0) ? channelTopics.join(" • ") : undefined,
parent:category, parent:ticketCategoryId,
reason:"Ticket Created By "+user.displayName, reason:"Ticket Created By "+user.displayName,
permissionOverwrites:permissions, permissionOverwrites:permissions,
rateLimitPerUser:slowMode rateLimitPerUser:slowMode
@@ -148,6 +121,7 @@ export const registerActions = async () => {
new api.ODTicketData("opendiscord:ticket-message",null), new api.ODTicketData("opendiscord:ticket-message",null),
new api.ODTicketData("opendiscord:participants",participants), new api.ODTicketData("opendiscord:participants",participants),
new api.ODTicketData("opendiscord:channel-suffix",channelSuffix), new api.ODTicketData("opendiscord:channel-suffix",channelSuffix),
new api.ODTicketData("opendiscord:channel-renamed",null),
new api.ODTicketData("opendiscord:previous-creators",[]), new api.ODTicketData("opendiscord:previous-creators",[]),
new api.ODTicketData("opendiscord:open",true), new api.ODTicketData("opendiscord:open",true),
@@ -167,8 +141,8 @@ export const registerActions = async () => {
new api.ODTicketData("opendiscord:pinned-on",null), new api.ODTicketData("opendiscord:pinned-on",null),
new api.ODTicketData("opendiscord:for-deletion",false), new api.ODTicketData("opendiscord:for-deletion",false),
new api.ODTicketData("opendiscord:category",category), new api.ODTicketData("opendiscord:category",ticketCategoryId ?? null),
new api.ODTicketData("opendiscord:category-mode",categoryMode), new api.ODTicketData("opendiscord:category-mode",ticketCategoryMode ?? null),
new api.ODTicketData("opendiscord:autoclose-enabled",option.get("opendiscord:autoclose-enable-hours").value), new api.ODTicketData("opendiscord:autoclose-enabled",option.get("opendiscord:autoclose-enable-hours").value),
new api.ODTicketData("opendiscord:autoclose-hours",(option.get("opendiscord:autoclose-enable-hours").value ? option.get("opendiscord:autoclose-hours").value : 0)), new api.ODTicketData("opendiscord:autoclose-hours",(option.get("opendiscord:autoclose-enable-hours").value ? option.get("opendiscord:autoclose-hours").value : 0)),
@@ -184,8 +158,8 @@ export const registerActions = async () => {
]) ])
//manage stats //manage stats
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-created",1,"increase") await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-created",1,"increase")
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-created",user.id,1,"increase") await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-created",user.id,1,"increase")
//manage bot permissions //manage bot permissions
await opendiscord.events.get("onTicketPermissionsCreated").emit([option,opendiscord.permissions,channel,user]) await opendiscord.events.get("onTicketPermissionsCreated").emit([option,opendiscord.permissions,channel,user])
@@ -197,7 +171,7 @@ export const registerActions = async () => {
instance.ticket = ticket instance.ticket = ticket
opendiscord.tickets.add(ticket) opendiscord.tickets.add(ticket)
}), }),
new api.ODWorker("opendiscord:send-ticket-message",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:send-ticket-message",2,async (instance,params,origin,cancel) => {
const {guild,user,answers,option} = params const {guild,user,answers,option} = params
const {ticket,channel} = instance const {ticket,channel} = instance
@@ -207,17 +181,23 @@ export const registerActions = async () => {
//check if ticket message is enabled //check if ticket message is enabled
if (!option.get("opendiscord:ticket-message-enabled").value) return if (!option.get("opendiscord:ticket-message-enabled").value) return
try { try {
const msg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build(source,{guild,channel,user,ticket})).message) const ticketMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build(origin,{guild,channel,user,ticket})).message)
ticket.get("opendiscord:ticket-message").value = msg.id if (ticketMsg) await interactiveMsgState.setMsgState({channel,message:ticketMsg},{
messageType:"ticket-message",
messageOrigin:"other",
messageAuthor:user.id
},false)
ticket.get("opendiscord:ticket-message").value = ticketMsg.id
//pin ticket message (if required) //pin ticket message (if required)
if (generalConfig.data.system.pinFirstTicketMessage && msg.pinnable) await msg.pin("Ticket Message") if (generalConfig.data.ticketSystem.pinFirstTicketMessage && ticketMsg.pinnable) await ticketMsg.pin("Ticket Message")
//manage stats //manage stats
await opendiscord.stats.get("opendiscord:ticket").setStat("opendiscord:messages-sent",ticket.id.value,1,"increase") await opendiscord.statistics.get("opendiscord:ticket").setStat("opendiscord:messages-sent",ticket.id.value,1,"increase")
await opendiscord.events.get("afterTicketMainMessageCreated").emit([ticket,msg,channel,user]) await opendiscord.events.get("afterTicketMainMessageCreated").emit([ticket,ticketMsg,channel,user])
}catch(err){ }catch(err){
process.emit("uncaughtException",err) process.emit("uncaughtException",err)
//something went wrong while sending the ticket message //something went wrong while sending the ticket message
@@ -225,20 +205,22 @@ export const registerActions = async () => {
} }
await opendiscord.events.get("afterTicketCreated").emit([ticket,user,channel]) await opendiscord.events.get("afterTicketCreated").emit([ticket,user,channel])
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,user,answers,option} = params const {guild,user,answers,option} = params
const {ticket,channel} = instance const {ticket,channel} = instance
if (!ticket || !channel) return opendiscord.log("Ticket Creation Error: Unable to send ticket message. Previous worker failed!","error")
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.creation.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.creation.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-logs").build(source,{guild,channel,user,ticket})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-logs").build(origin,{guild,channel,user,ticket}))
} }
//to dm //to dm
if (generalConfig.data.system.messages.creation.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-dm").build(source,{guild,channel,user,ticket})) if (generalConfig.data.logs.logMessages.creation.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-dm").build(origin,{guild,channel,user,ticket}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,user,answers,option} = params const {guild,user,answers,option} = params
const {ticket,channel} = instance const {ticket,channel} = instance
@@ -249,7 +231,7 @@ export const registerActions = async () => {
{key:"userid",value:user.id,hidden:true}, {key:"userid",value:user.id,hidden:true},
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"method",value:source}, {key:"method",value:origin},
{key:"option",value:option.id.value} {key:"option",value:option.id.value}
]) ])
}) })
+10 -10
View File
@@ -1,13 +1,13 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET CREATION SYSTEM //TICKET CREATION SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:create-ticket-permissions")) opendiscord.actions.add(new api.ODAction("opendiscord:create-ticket-permissions"))
opendiscord.actions.get("opendiscord:create-ticket-permissions").workers.add([ opendiscord.actions.get("opendiscord:create-ticket-permissions").workers.add([
new api.ODWorker("opendiscord:check-blacklist",4,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:check-blacklist",4,(instance,params,origin,cancel) => {
if (!params.option.get("opendiscord:allow-blacklisted-users").value && opendiscord.blacklist.exists(params.user.id)){ if (!params.option.get("opendiscord:allow-blacklisted-users").value && opendiscord.blacklist.exists(params.user.id)){
instance.valid = false instance.valid = false
instance.reason = "blacklist" instance.reason = "blacklist"
@@ -19,7 +19,7 @@ export const registerActions = async () => {
return cancel() return cancel()
} }
}), }),
new api.ODWorker("opendiscord:check-cooldown",3,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:check-cooldown",3,(instance,params,origin,cancel) => {
const cooldown = opendiscord.cooldowns.get("opendiscord:option-cooldown_"+params.option.id.value) const cooldown = opendiscord.cooldowns.get("opendiscord:option-cooldown_"+params.option.id.value)
if (cooldown && cooldown instanceof api.ODTimeoutCooldown && cooldown.use(params.user.id)){ if (cooldown && cooldown instanceof api.ODTimeoutCooldown && cooldown.use(params.user.id)){
instance.valid = false instance.valid = false
@@ -36,16 +36,16 @@ export const registerActions = async () => {
return cancel() return cancel()
} }
}), }),
new api.ODWorker("opendiscord:check-global-limits",2,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:check-global-limits",2,(instance,params,origin,cancel) => {
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
if (!generalConfig.data.system.limits.enabled) return if (!generalConfig.data.ticketSystem.limits.enabled) return
const allTickets = opendiscord.tickets.getAll() const allTickets = opendiscord.tickets.getAll()
const globalTicketCount = allTickets.length const globalTicketCount = allTickets.length
const userTickets = opendiscord.tickets.getFiltered((ticket) => ticket.exists("opendiscord:opened-by") && (ticket.get("opendiscord:opened-by").value == params.user.id)) const userTickets = opendiscord.tickets.getFiltered((ticket) => ticket.exists("opendiscord:opened-by") && (ticket.get("opendiscord:opened-by").value == params.user.id))
const userTicketCount = userTickets.length const userTicketCount = userTickets.length
if (globalTicketCount >= generalConfig.data.system.limits.globalMaximum){ if (globalTicketCount >= generalConfig.data.ticketSystem.limits.globalMaximum){
instance.valid = false instance.valid = false
instance.reason = "global-limit" instance.reason = "global-limit"
opendiscord.log(params.user.displayName+" tried to create a ticket but reached the limit!","info",[ opendiscord.log(params.user.displayName+" tried to create a ticket but reached the limit!","info",[
@@ -55,7 +55,7 @@ export const registerActions = async () => {
{key:"limit",value:"global"} {key:"limit",value:"global"}
]) ])
return cancel() return cancel()
}else if (userTicketCount >= generalConfig.data.system.limits.userMaximum){ }else if (userTicketCount >= generalConfig.data.ticketSystem.limits.userMaximum){
instance.valid = false instance.valid = false
instance.reason = "global-user-limit" instance.reason = "global-user-limit"
opendiscord.log(params.user.displayName+" tried to create a ticket, but reached the limit!","info",[ opendiscord.log(params.user.displayName+" tried to create a ticket, but reached the limit!","info",[
@@ -67,7 +67,7 @@ export const registerActions = async () => {
return cancel() return cancel()
} }
}), }),
new api.ODWorker("opendiscord:check-option-limits",1,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:check-option-limits",1,(instance,params,origin,cancel) => {
if (!params.option.exists("opendiscord:limits-enabled") || !params.option.get("opendiscord:limits-enabled").value) return if (!params.option.exists("opendiscord:limits-enabled") || !params.option.get("opendiscord:limits-enabled").value) return
const allTickets = opendiscord.tickets.getFiltered((ticket) => ticket.option.id.value == params.option.id.value) const allTickets = opendiscord.tickets.getFiltered((ticket) => ticket.option.id.value == params.option.id.value)
@@ -97,7 +97,7 @@ export const registerActions = async () => {
return cancel() return cancel()
} }
}), }),
new api.ODWorker("opendiscord:valid",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:valid",0,(instance,params,origin,cancel) => {
instance.valid = true instance.valid = true
instance.reason = null instance.reason = null
cancel() cancel()
+40 -14
View File
@@ -1,15 +1,15 @@
/////////////////////////////////////// ///////////////////////////////////////
//TRANSCRIPT CREATION SYSTEM //TRANSCRIPT CREATION SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts") const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:create-transcript")) opendiscord.actions.add(new api.ODAction("opendiscord:create-transcript"))
opendiscord.actions.get("opendiscord:create-transcript").workers.add([ opendiscord.actions.get("opendiscord:create-transcript").workers.add([
new api.ODWorker("opendiscord:select-compiler",4,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:select-compiler",4,async (instance,params,origin,cancel) => {
const {channel,user,ticket} = params const {channel,user,ticket} = params
if (channel.type != discord.ChannelType.GuildText) return cancel() if (channel.type != discord.ChannelType.GuildText) return cancel()
if (!transcriptConfig.data.general.enabled) return cancel() if (!transcriptConfig.data.general.enabled) return cancel()
@@ -29,10 +29,15 @@ export const registerActions = async () => {
if (transcriptConfig.data.general.mode == "text") instance.compiler = opendiscord.transcripts.get("opendiscord:text-compiler") if (transcriptConfig.data.general.mode == "text") instance.compiler = opendiscord.transcripts.get("opendiscord:text-compiler")
else if (transcriptConfig.data.general.mode == "html") instance.compiler = opendiscord.transcripts.get("opendiscord:html-compiler") else if (transcriptConfig.data.general.mode == "html") instance.compiler = opendiscord.transcripts.get("opendiscord:html-compiler")
}), }),
new api.ODWorker("opendiscord:init-transcript",3,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:init-transcript",3,async (instance,params,origin,cancel) => {
const {channel,user,ticket} = params const {channel,user,ticket} = params
if (channel.type != discord.ChannelType.GuildText) return cancel() if (channel.type != discord.ChannelType.GuildText) return cancel()
if (!transcriptConfig.data.general.enabled) return cancel() if (!transcriptConfig.data.general.enabled) return cancel()
if (!instance.compiler){
instance.success = false
cancel()
throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:init-transcript) => Instance is missing transcript compiler!")
}
//run transcript compiler init() //run transcript compiler init()
await opendiscord.events.get("onTranscriptInit").emit([opendiscord.transcripts,ticket,channel,user]) await opendiscord.events.get("onTranscriptInit").emit([opendiscord.transcripts,ticket,channel,user])
@@ -63,7 +68,7 @@ export const registerActions = async () => {
} }
await opendiscord.events.get("afterTranscriptInitiated").emit([opendiscord.transcripts,ticket,channel,user]) await opendiscord.events.get("afterTranscriptInitiated").emit([opendiscord.transcripts,ticket,channel,user])
}), }),
new api.ODWorker("opendiscord:compile-transcript",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:compile-transcript",2,async (instance,params,origin,cancel) => {
const {channel,user,ticket} = params const {channel,user,ticket} = params
if (channel.type != discord.ChannelType.GuildText) return cancel() if (channel.type != discord.ChannelType.GuildText) return cancel()
if (!instance.compiler){ if (!instance.compiler){
@@ -71,6 +76,11 @@ export const registerActions = async () => {
cancel() cancel()
throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:compile-transcript) => Instance is missing transcript compiler!") throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:compile-transcript) => Instance is missing transcript compiler!")
} }
if (typeof instance.initData == "undefined"){
instance.success = false
cancel()
throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:compile-transcript) => Instance is missing transcript initData!")
}
//run transcript compiler compile() //run transcript compiler compile()
await opendiscord.events.get("onTranscriptCompile").emit([opendiscord.transcripts,ticket,channel,user]) await opendiscord.events.get("onTranscriptCompile").emit([opendiscord.transcripts,ticket,channel,user])
@@ -93,15 +103,31 @@ export const registerActions = async () => {
} }
await opendiscord.events.get("afterTranscriptCompiled").emit([opendiscord.transcripts,ticket,channel,user]) await opendiscord.events.get("afterTranscriptCompiled").emit([opendiscord.transcripts,ticket,channel,user])
}), }),
new api.ODWorker("opendiscord:ready-transcript",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:ready-transcript",1,async (instance,params,origin,cancel) => {
if (!instance.compiler){
instance.success = false
cancel()
throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript compiler! (1)")
}
if (!instance.result){ if (!instance.result){
instance.success = false instance.success = false
cancel() cancel()
throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript result!") throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript result! (1)")
} }
//run transcript compiler ready() //run transcript compiler ready()
utilities.runAsync(async () => { utilities.runAsync(async () => {
if (!instance.compiler){
instance.success = false
cancel()
throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript compiler! (2)")
}
if (!instance.result){
instance.success = false
cancel()
throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript result! (2)")
}
await opendiscord.events.get("onTranscriptReady").emit([opendiscord.transcripts,instance.result.ticket,instance.result.channel,instance.result.user]) await opendiscord.events.get("onTranscriptReady").emit([opendiscord.transcripts,instance.result.ticket,instance.result.channel,instance.result.user])
if (instance.compiler.ready){ if (instance.compiler.ready){
try{ try{
@@ -109,9 +135,9 @@ export const registerActions = async () => {
//send channel message //send channel message
if (transcriptConfig.data.general.enableChannel && channelMessage){ if (transcriptConfig.data.general.enableChannel && channelMessage){
if (instance.pendingMessage && instance.pendingMessage.message && instance.pendingMessage.success){ if (instance.pendingMessage && instance.pendingMessage.success){
//edit "pending" message to be the "ready" message //edit "pending" message to be the "ready" message
instance.pendingMessage.message.edit(channelMessage.message) instance.pendingMessage.message.edit(utilities.getMessageFromBuildResult(channelMessage,"message"))
}else{ }else{
//send ready message to channel //send ready message to channel
const post = opendiscord.posts.get("opendiscord:transcripts") const post = opendiscord.posts.get("opendiscord:transcripts")
@@ -149,11 +175,11 @@ export const registerActions = async () => {
}) })
//update stats //update stats
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:transcripts-created",1,"increase") await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:transcripts-created",1,"increase")
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:transcripts-created",params.user.id,1,"increase") await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:transcripts-created",params.user.id,1,"increase")
await opendiscord.events.get("afterTranscriptCreated").emit([opendiscord.transcripts,instance.result.ticket,instance.result.channel,instance.result.user]) await opendiscord.events.get("afterTranscriptCreated").emit([opendiscord.transcripts,instance.result.ticket,instance.result.channel,instance.result.user])
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {user,channel,ticket} = params const {user,channel,ticket} = params
opendiscord.log(user.displayName+" created a transcript!","info",[ opendiscord.log(user.displayName+" created a transcript!","info",[
{key:"user",value:user.username}, {key:"user",value:user.username},
@@ -161,8 +187,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"option",value:ticket.option.id.value}, {key:"option",value:ticket.option.id.value},
{key:"method",value:source,hidden:true}, {key:"method",value:origin,hidden:true},
{key:"compiler",value:instance.compiler.id.value}, {key:"compiler",value:instance.compiler?.id.value ?? "<unknown-compiler>"},
]) ])
}) })
]) ])
+17 -383
View File
@@ -1,16 +1,16 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET DELETION SYSTEM //TICKET DELETION SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages const lang = opendiscord.languages
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:delete-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:delete-ticket"))
opendiscord.actions.get("opendiscord:delete-ticket").workers.add([ opendiscord.actions.get("opendiscord:delete-ticket").workers.add([
new api.ODWorker("opendiscord:delete-ticket",3,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:delete-ticket",3,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to delete ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to delete ticket! Open Ticket doesn't support threads!")
@@ -20,31 +20,18 @@ export const registerActions = async () => {
ticket.get("opendiscord:for-deletion").value = true ticket.get("opendiscord:for-deletion").value = true
ticket.get("opendiscord:busy").value = true ticket.get("opendiscord:busy").value = true
//update ticket message //update ticket message (no await)
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket) openticketUtils.updateTicketMessage(guild,channel,user,ticket)
if (ticketMessage){
try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
}catch(e){
opendiscord.log("Unable to edit ticket message on ticket deletion!","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"messageid",value:ticketMessage.id},
{key:"option",value:ticket.option.id.value}
])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(source,{guild,channel,user,ticket,reason})).message) if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(origin,{guild,channel,user,ticket,reason})).message)
//create transcript //create transcript
if (!params.withoutTranscript){ if (!params.withoutTranscript){
const transcriptRes = await opendiscord.actions.get("opendiscord:create-transcript").run(source,{guild,channel,user,ticket}) const transcriptRes = await opendiscord.actions.get("opendiscord:create-transcript").run(origin,{guild,channel,user,ticket})
//transcript failure //transcript failure
if (typeof transcriptRes.success == "boolean" && !transcriptRes.success && transcriptRes.compiler){ if (typeof transcriptRes.success == "boolean" && !transcriptRes.success && transcriptRes.compiler){
const {compiler} = transcriptRes const {compiler} = transcriptRes
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:transcript-error").build(source,{guild,channel,user,ticket,compiler,reason:transcriptRes.errorReason ?? null})).message) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:transcript-error").build(origin,{guild,channel,user,ticket,compiler,reason:transcriptRes.errorReason ?? null})).message)
.catch((reason) => opendiscord.log("Unable to send transcript failure to ticket channel!","error",[{key:"id",value:channel.id}])) .catch((reason) => opendiscord.log("Unable to send transcript failure to ticket channel!","error",[{key:"id",value:channel.id}]))
//undo deletion //undo deletion
@@ -59,8 +46,8 @@ export const registerActions = async () => {
} }
//update stats //update stats
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-deleted",1,"increase") await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-deleted",1,"increase")
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-deleted",user.id,1,"increase") await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-deleted",user.id,1,"increase")
//delete ticket from manager //delete ticket from manager
opendiscord.tickets.remove(ticket.id) opendiscord.tickets.remove(ticket.id)
@@ -68,21 +55,21 @@ export const registerActions = async () => {
//delete permissions from manager //delete permissions from manager
await (await import("../data/framework/permissionLoader.js")).removeTicketPermissions(ticket) await (await import("../data/framework/permissionLoader.js")).removeTicketPermissions(ticket)
}), }),
new api.ODWorker("opendiscord:discord-logs",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",2,async (instance,params,origin,cancel) => {
//logs before channel deletion => channel might still be used in log embeds //logs before channel deletion => channel might still be used in log embeds
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.deleting.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.deleting.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"delete",reason,additionalData:null})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"delete",reason,additionalData:null}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.deleting.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"delete",reason,additionalData:null})) if (creator && generalConfig.data.logs.logMessages.deleting.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"delete",reason,additionalData:null}))
}), }),
new api.ODWorker("opendiscord:delete-channel",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:delete-channel",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
//delete channel & events //delete channel & events
await opendiscord.events.get("onTicketChannelDeletion").emit([ticket,channel,user]) await opendiscord.events.get("onTicketChannelDeletion").emit([ticket,channel,user])
@@ -94,7 +81,7 @@ export const registerActions = async () => {
await opendiscord.events.get("afterTicketDeleted").emit([ticket,user,reason]) await opendiscord.events.get("afterTicketDeleted").emit([ticket,user,reason])
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" deleted a ticket!","info",[ opendiscord.log(user.displayName+" deleted a ticket!","info",[
@@ -103,7 +90,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source}, {key:"method",value:origin},
{key:"transcript",value:(!params.withoutTranscript).toString()}, {key:"transcript",value:(!params.withoutTranscript).toString()},
]) ])
}) })
@@ -114,356 +101,3 @@ export const registerActions = async () => {
params.ticket.get("opendiscord:for-deletion").value = false params.ticket.get("opendiscord:for-deletion").value = false
}) })
} }
export const registerVerifyBars = async () => {
//DELETE TICKET TICKET MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:delete-ticket-ticket-message").success.add([
new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
const {user,member,channel,guild} = instance
//check permissions
const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild)
if (!permsResult.hasPerms){
if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
return cancel()
}
//don't allow deleteWithoutTranscript to non-global-admins when enabled
if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}
}
//check is in guild/server
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
//check if ticket exists
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//return when not allowed because of missing messages
if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
}
//start deleting ticket
if (params.data == "reason"){
//delete with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
}else{
//delete without reason
await instance.defer("update",false)
//don't await DELETE action => else it will update the message after the channel has been deleted
opendiscord.actions.get("opendiscord:delete-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true,withoutTranscript:(params.data == "no-transcript")})
//update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
ticket.get("opendiscord:for-deletion").value = true
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
}
})
])
opendiscord.verifybars.get("opendiscord:delete-ticket-ticket-message").failure.add([
new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
})
])
//DELETE TICKET CLOSE MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-close-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-close-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:delete-ticket-close-message").success.add([
new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
const {user,member,channel,guild} = instance
//check permissions
const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild)
if (!permsResult.hasPerms){
if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
return cancel()
}
//don't allow deleteWithoutTranscript to non-global-admins when enabled
if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}
}
//check is in guild/server
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
//check if ticket exists
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//return when not allowed because of missing messages
if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
}
//start deleting ticket
if (params.data == "reason"){
//delete with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("close-message",{guild,channel,user,ticket}))
}else{
//delete without reason
await instance.defer("update",false)
//don't await DELETE action => else it will update the message after the channel has been deleted
opendiscord.actions.get("opendiscord:delete-ticket").run("close-message",{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript:(params.data == "no-transcript")})
//update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
ticket.get("opendiscord:for-deletion").value = true
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("close-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:delete-ticket-close-message").failure.add([
new api.ODWorker("opendiscord:back-to-close-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason}))
})
])
//DELETE TICKET REOPEN MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-reopen-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-reopen-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:delete-ticket-reopen-message").success.add([
new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
const {user,member,channel,guild} = instance
//check permissions
const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild)
if (!permsResult.hasPerms){
if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
return cancel()
}
//don't allow deleteWithoutTranscript to non-global-admins when enabled
if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}
}
//check is in guild/server
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
//check if ticket exists
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//return when not allowed because of missing messages
if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
}
//start deleting ticket
if (params.data == "reason"){
//delete with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("reopen-message",{guild,channel,user,ticket}))
}else{
//delete without reason
await instance.defer("update",false)
//don't await DELETE action => else it will update the message after the channel has been deleted
opendiscord.actions.get("opendiscord:delete-ticket").run("reopen-message",{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript:(params.data == "no-transcript")})
//update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
ticket.get("opendiscord:for-deletion").value = true
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("reopen-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:delete-ticket-reopen-message").failure.add([
new api.ODWorker("opendiscord:back-to-reopen-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason}))
})
])
//DELETE TICKET AUTOCLOSE MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-autoclose-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-autoclose-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:delete-ticket-autoclose-message").success.add([
new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
const {user,member,channel,guild} = instance
//check permissions
const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild)
if (!permsResult.hasPerms){
if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
return cancel()
}
//don't allow deleteWithoutTranscript to non-global-admins when enabled
if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}
}
//check is in guild/server
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
//check if ticket exists
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//return when not allowed because of missing messages
if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return cancel()
}
}
//start deleting ticket
if (params.data == "reason"){
//delete with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("autoclose-message",{guild,channel,user,ticket}))
}else{
//delete without reason
await instance.defer("update",false)
//don't await DELETE action => else it will update the message after the channel has been deleted
opendiscord.actions.get("opendiscord:delete-ticket").run("autoclose-message",{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript:(params.data == "no-transcript")})
//update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
ticket.get("opendiscord:for-deletion").value = true
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("autoclose-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:delete-ticket-autoclose-message").failure.add([
new api.ODWorker("opendiscord:back-to-autoclose-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("other",{guild,channel,user,ticket}))
})
])
}
+46 -112
View File
@@ -1,76 +1,43 @@
/////////////////////////////////////// ///////////////////////////////////////
//TRANSCRIPT ERROR SYSTEM //TRANSCRIPT ERROR SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerButtonResponders = async () => { export async function registerButtonResponders(){
//TRANSCRIPT ERROR RETRY //TRANSCRIPT ERROR RETRY
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:transcript-error-retry",/^od:transcript-error-retry_([^_]+)/)) opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:transcript-error-retry",/^od:transcript-error-retry_([^_]+)/))
opendiscord.responders.buttons.get("opendiscord:transcript-error-retry").workers.add([ opendiscord.responders.buttons.get("opendiscord:transcript-error-retry").workers.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => {
const permissionMode = generalConfig.data.system.permissions.delete const {guild,channel,user,member} = instance
if (permissionMode == "none"){ //responder checks
//no permissions const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) if (!hasPerms) return cancel()
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const originalSource = instance.interaction.customId.split("_")[1] as api.ODActionManagerIds_Default["opendiscord:delete-ticket"]["source"]
if (!guild){ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) if (!isInGuild || !guild || channel.isDMBased()) return cancel()
return cancel()
} const ticket = await openticketUtils.replyIsTicket(instance,origin)
const ticket = opendiscord.tickets.get(channel.id) if (!ticket) return cancel()
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
return cancel() if (!isAvailable) return cancel()
}
//return when busy //fetch data
if (ticket.get("opendiscord:busy").value){ const originalOrigin = instance.interaction.customId.split("_")[1] as api.ODActionManagerIdMappings["opendiscord:delete-ticket"]["origin"]
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start deleting ticket (without reason) //start deleting ticket (without reason)
await instance.defer("update",false) await instance.defer("update",false)
//don't await DELETE action => else it will update the message after the channel has been deleted //don't await DELETE action => else it will update the message after the channel has been deleted
opendiscord.actions.get("opendiscord:delete-ticket").run(originalSource,{guild,channel,user,ticket,reason:"Transcript Error (Retried)",sendMessage:false,withoutTranscript:false}) opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{guild,channel,user,ticket,reason:"Transcript Error (Retried)",sendMessage:false,withoutTranscript:false})
//update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
ticket.get("opendiscord:for-deletion").value = true
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason:"Transcript Error (Retried)"}))
ticket.get("opendiscord:for-deletion").value = true //disable ticket message buttons
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason:"Transcript Error (Retried)"}))
}), }),
new api.ODWorker("opendiscord:logs",-1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",-1,async (instance,params,origin,cancel) => {
const {user,channel} = instance const {user,channel} = instance
if (channel.isDMBased()) return if (channel.isDMBased()) return
opendiscord.log(user.displayName+" retried deleting a ticket with transcript!","info",[ opendiscord.log(user.displayName+" retried deleting a ticket with transcript!","info",[
@@ -78,7 +45,7 @@ export const registerButtonResponders = async () => {
{key:"userid",value:user.id,hidden:true}, {key:"userid",value:user.id,hidden:true},
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
@@ -86,68 +53,35 @@ export const registerButtonResponders = async () => {
//TRANSCRIPT ERROR CONTINUE //TRANSCRIPT ERROR CONTINUE
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:transcript-error-continue",/^od:transcript-error-continue_([^_]+)/)) opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:transcript-error-continue",/^od:transcript-error-continue_([^_]+)/))
opendiscord.responders.buttons.get("opendiscord:transcript-error-continue").workers.add([ opendiscord.responders.buttons.get("opendiscord:transcript-error-continue").workers.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => {
const permissionMode = generalConfig.data.system.permissions.delete
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance const {guild,channel,user} = instance
const originalSource = instance.interaction.customId.split("_")[1] as api.ODActionManagerIds_Default["opendiscord:delete-ticket"]["source"]
if (!guild){ //responder checks
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
return cancel() if (!hasPerms) return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start deleting ticket (without reason) const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
if (!isInGuild || !guild || channel.isDMBased()) return cancel()
const ticket = await openticketUtils.replyIsTicket(instance,origin)
if (!ticket) return cancel()
const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
if (!isAvailable) return cancel()
//fetch data
const originalOrigin = instance.interaction.customId.split("_")[1] as api.ODActionManagerIdMappings["opendiscord:delete-ticket"]["origin"]
//start deleting ticket (without reason & without transcript)
await instance.defer("update",false) await instance.defer("update",false)
//don't await DELETE action => else it will update the message after the channel has been deleted //don't await DELETE action => else it will update the message after the channel has been deleted
opendiscord.actions.get("opendiscord:delete-ticket").run(originalSource,{guild,channel,user,ticket,reason:"Transcript Error (Continued)",sendMessage:false,withoutTranscript:true}) opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{guild,channel,user,ticket,reason:"Transcript Error (Continued)",sendMessage:false,withoutTranscript:true})
//update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
ticket.get("opendiscord:for-deletion").value = true ticket.get("opendiscord:for-deletion").value = true //disable ticket message buttons
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason:"Transcript Error (Continued)"})) await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason:"Transcript Error (Continued)"}))
}), }),
new api.ODWorker("opendiscord:logs",-1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",-1,async (instance,params,origin,cancel) => {
const {user,channel} = instance const {user,channel} = instance
if (channel.isDMBased()) return if (channel.isDMBased()) return
opendiscord.log(user.displayName+" continued deleting a ticket without transcript!","info",[ opendiscord.log(user.displayName+" continued deleting a ticket without transcript!","info",[
@@ -155,7 +89,7 @@ export const registerButtonResponders = async () => {
{key:"userid",value:user.id,hidden:true}, {key:"userid",value:user.id,hidden:true},
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
+13 -23
View File
@@ -1,32 +1,22 @@
/////////////////////////////////////// ///////////////////////////////////////
//VERIFYBAR SYSTEM //VERIFYBAR SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
export const registerButtonResponders = async () => { export async function registerButtonResponders(){
//VERIFYBAR SUCCESS //HANDLE VERIFYBAR BUTTON
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-success",/^od:verifybar-success_([^_]+)/)) opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-button",/^od:verifybar\|([^|]+)\|([^|]+)/))
opendiscord.responders.buttons.get("opendiscord:verifybar-success").workers.add( opendiscord.responders.buttons.get("opendiscord:verifybar-button").workers.add(
new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,origin,cancel) => {
const id = instance.interaction.customId.split("_")[1] const match = /^od:verifybar\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
const customData = instance.interaction.customId.split("_")[2] as string|undefined if (!match) return cancel()
const verifyBarId = match[1]
const verifyButtonId = match[2]
const verifybar = opendiscord.verifybars.get(id) const verifybar = opendiscord.verifybars.get(verifyBarId)
if (!verifybar) return if (!verifybar) return
if (verifybar.success) await verifybar.success.executeWorkers(instance,"verifybar",{data:customData ?? null,verifybarMessage:instance.message}) await verifybar.activate(instance,verifyButtonId)
})
)
//VERIFYBAR FAILURE
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-failure",/^od:verifybar-failure_([^_]+)/))
opendiscord.responders.buttons.get("opendiscord:verifybar-failure").workers.add(
new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,source,cancel) => {
const id = instance.interaction.customId.split("_")[1]
const customData = instance.interaction.customId.split("_")[2] as string|undefined
const verifybar = opendiscord.verifybars.get(id)
if (!verifybar) return
if (verifybar.failure) await verifybar.failure.executeWorkers(instance,"verifybar",{data:customData ?? null,verifybarMessage:instance.message})
}) })
) )
} }
+47 -102
View File
@@ -1,15 +1,15 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET MOVING SYSTEM //TICKET MOVING SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:move-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:move-ticket"))
opendiscord.actions.get("opendiscord:move-ticket").workers.add([ opendiscord.actions.get("opendiscord:move-ticket").workers.add([
new api.ODWorker("opendiscord:move-ticket",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:move-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params const {guild,channel,user,ticket,reason,data} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to move ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to move ticket! Open Ticket doesn't support threads!")
@@ -17,78 +17,31 @@ export const registerActions = async () => {
ticket.option = data ticket.option = data
//update stats //update stats
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-moved",1,"increase") await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-moved",1,"increase")
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-moved",user.id,1,"increase") await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-moved",user.id,1,"increase")
//get new channel properties //calculate & update category
const channelPrefix = ticket.option.get("opendiscord:channel-prefix").value const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("move-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
const channelSuffix = ticket.get("opendiscord:channel-suffix").value if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
const channelCategory = ticket.option.get("opendiscord:channel-category").value const originalCategoryName = channel.parent?.name ?? "<unknown>"
const channelBackupCategory = ticket.option.get("opendiscord:channel-category-backup").value const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
const rawClaimCategory = ticket.option.get("opendiscord:channel-categories-claimed").value.find((c) => c.user == user.id) try{
const claimCategory = (rawClaimCategory) ? rawClaimCategory.category : null await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
const closeCategory = ticket.option.get("opendiscord:channel-category-closed").value process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
const channelTopic = ticket.option.get("opendiscord:channel-topic").value })
ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
//handle category ticket.get("opendiscord:category").value = categoryResult.newCategoryId
let category: string|null = null }catch(err){
let categoryMode: "backup"|"normal"|"closed"|"claimed"|null = null const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-move",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
if (claimCategory){ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
//use claim category opendiscord.log("Unable to move ticket to moved category.","error",[
category = claimCategory {key:"channel",value:"#"+channel.name},
categoryMode = "claimed" {key:"channelid",value:channel.id,hidden:true},
}else if (closeCategory != "" && ticket.get("opendiscord:closed").value){ {key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
//use close category
category = closeCategory
categoryMode = "closed"
}else if (channelCategory != ""){
//category enabled
const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory)
if (!normalCategory){
//default category was not found
opendiscord.log("Ticket Move Error: Unable to find category! #1","error",[
{key:"categoryid",value:channelCategory},
{key:"backup",value:"false"}
]) ])
}else{
//default category was found
if (normalCategory.children.cache.size >= 50 && channelBackupCategory != ""){
//use backup category
const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelBackupCategory)
if (!backupCategory){
//default category was not found
opendiscord.log("Ticket Move Error: Unable to find category! #2","error",[
{key:"categoryid",value:channelBackupCategory},
{key:"backup",value:"true"}
])
}else{
category = backupCategory.id
categoryMode = "backup"
}
}else{
//use default category
category = normalCategory.id
categoryMode = "normal"
}
} }
} }
try {
//only move category when not the same.
if (channel.parentId != category) await utilities.timedAwait(channel.setParent(category,{lockPermissions:false}),2500,(err) => {
opendiscord.log("Failed to change channel category on ticket move","error")
})
ticket.get("opendiscord:category-mode").value = categoryMode
ticket.get("opendiscord:category").value = category
}catch(e){
opendiscord.log("Unable to move ticket to 'moved category'!","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"categoryid",value:category ?? "/"}
])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
//handle permissions //handle permissions
const permissions: discord.OverwriteResolvable[] = [{ const permissions: discord.OverwriteResolvable[] = [{
type:discord.OverwriteType.Role, type:discord.OverwriteType.Role,
@@ -153,58 +106,50 @@ export const registerActions = async () => {
ticket.get("opendiscord:participants").value = participants ticket.get("opendiscord:participants").value = participants
ticket.get("opendiscord:participants").refreshDatabase() ticket.get("opendiscord:participants").refreshDatabase()
//rename channel (and give error when crashed) //calculate channel name
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : "" const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("move-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? "" if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
const originalName = channel.name
const originalName = channel.name const newName = channelNameResult.newChannelName
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channelPrefix+channelSuffix)
try{
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
opendiscord.log("Failed to rename channel on ticket move","error")
})
}catch(err){
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-move",{guild,channel,user,originalName,newName:newName})).message)
}
//update ticket message
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
if (ticketMessage){
try{ try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message) await utilities.timedAwait(channel.setName(newName),2500,(err) => {
}catch(e){ opendiscord.log("Failed to rename channel on ticket move","error")
opendiscord.log("Unable to edit ticket message on ticket moving!","error",[ })
{key:"channel",value:"#"+channel.name}, }catch(err){
{key:"channelid",value:channel.id,hidden:true}, opendiscord.log("Unable to rename channel while moving ticket! Waiting until ratelimit expires...","warning",[
{key:"messageid",value:ticketMessage.id}, {key:"oldName",value:originalName},
{key:"option",value:ticket.option.id.value} {key:"newName",value:newName}
]) ])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException")) const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-move",{guild,channel,user,originalName,newName})).message)
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
} }
} }
//update ticket message (no await)
openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:move-message").build(source,{guild,channel,user,ticket,reason,data})).message) if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:move-message").build(origin,{guild,channel,user,ticket,reason,data})).message)
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketMoved").emit([ticket,user,channel,reason]) await opendiscord.events.get("afterTicketMoved").emit([ticket,user,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params const {guild,channel,user,ticket,reason,data} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.moving.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.moving.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"move",reason,additionalData:data})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"move",reason,additionalData:data}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.moving.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"move",reason,additionalData:data})) if (creator && generalConfig.data.logs.logMessages.moving.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"move",reason,additionalData:data}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" moved a ticket!","info",[ opendiscord.log(user.displayName+" moved a ticket!","info",[
@@ -213,7 +158,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
+38 -221
View File
@@ -1,15 +1,16 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET PINNING SYSTEM //TICKET PINNING SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:pin-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:pin-ticket"))
opendiscord.actions.get("opendiscord:pin-ticket").workers.add([ opendiscord.actions.get("opendiscord:pin-ticket").workers.add([
new api.ODWorker("opendiscord:pin-ticket",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:pin-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to pin ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to pin ticket! Open Ticket doesn't support threads!")
@@ -22,66 +23,66 @@ export const registerActions = async () => {
ticket.get("opendiscord:busy").value = true ticket.get("opendiscord:busy").value = true
//update stats //update stats
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-pinned",1,"increase") await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-pinned",1,"increase")
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-pinned",user.id,1,"increase") await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-pinned",user.id,1,"increase")
//move to top of category //move to top of category
if (channel.parent){ if (channel.parent){
await channel.setPosition(0,{reason:"Ticket Pinned!"}) await channel.setPosition(0,{reason:"Ticket Pinned!"})
} }
//rename channel (and give error when crashed) //calculate channel name
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : "" const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("pin-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? "" if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
const originalName = channel.name
const originalName = channel.name const newName = channelNameResult.newChannelName
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channel.name)
try{
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
opendiscord.log("Failed to rename channel on ticket pin","error")
})
}catch(err){
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-pin",{guild,channel,user,originalName,newName})).message)
}
//update ticket message
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
if (ticketMessage){
try{ try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message) await utilities.timedAwait(channel.setName(newName),2500,(err) => {
}catch(e){ opendiscord.log("Failed to rename channel on ticket pin","error")
opendiscord.log("Unable to edit ticket message on ticket pinning!","error",[ })
{key:"channel",value:"#"+channel.name}, }catch(err){
{key:"channelid",value:channel.id,hidden:true}, opendiscord.log("Unable to rename channel while pinning ticket! Waiting until ratelimit expires...","warning",[
{key:"message",value:ticketMessage.id}, {key:"oldName",value:originalName},
{key:"option",value:ticket.option.id.value} {key:"newName",value:newName}
]) ])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException")) const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-pin",{guild,channel,user,originalName,newName})).message)
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
} }
} }
//update ticket message (no await)
openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(source,{guild,channel,user,ticket,reason})).message) if (params.sendMessage){
const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(origin,{guild,channel,user,ticket,reason})).message)
if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
messageType:"pin-message",
messageOrigin:"other",
messageAuthor:user.id,
messageReason:reason
},false)
}
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketPinned").emit([ticket,user,channel,reason]) await opendiscord.events.get("afterTicketPinned").emit([ticket,user,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.pinning.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.pinning.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"pin",reason,additionalData:null})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"pin",reason,additionalData:null}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.pinning.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"pin",reason,additionalData:null})) if (creator && generalConfig.data.logs.logMessages.pinning.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"pin",reason,additionalData:null}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" pinned a ticket!","info",[ opendiscord.log(user.displayName+" pinned a ticket!","info",[
@@ -90,192 +91,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
} }
export const registerVerifyBars = async () => {
//PIN TICKET TICKET MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:pin-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:pin-ticket-ticket-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.pin
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when already pinned
if (ticket.get("opendiscord:pinned").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start pinning ticket
if (params.data == "reason"){
//pin with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:pin-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
}else{
//pin without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:pin-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
}
})
])
opendiscord.verifybars.get("opendiscord:pin-ticket-ticket-message").failure.add([
new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
})
])
//PIN TICKET UNPIN MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:pin-ticket-unpin-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-unpin-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:pin-ticket-unpin-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.pin
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when already pinned
if (ticket.get("opendiscord:pinned").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start pinning ticket
if (params.data == "reason"){
//pin with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:pin-ticket-reason").build("unpin-message",{guild,channel,user,ticket}))
}else{
//pin without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:pin-ticket").run("unpin-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("unpin-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:pin-ticket-unpin-message").failure.add([
new api.ODWorker("opendiscord:back-to-unpin-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("other",{guild,channel,user,ticket,reason}))
})
])
opendiscord.actions.get("opendiscord:pin-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => {
//set busy to false in case of crash or cancel
params.ticket.get("opendiscord:busy").value = false
})
}
+9 -9
View File
@@ -1,15 +1,15 @@
/////////////////////////////////////// ///////////////////////////////////////
//REACTION ROLE SYSTEM //REACTION ROLE SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:reaction-role")) opendiscord.actions.add(new api.ODAction("opendiscord:reaction-role"))
opendiscord.actions.get("opendiscord:reaction-role").workers.add([ opendiscord.actions.get("opendiscord:reaction-role").workers.add([
new api.ODWorker("opendiscord:reaction-role",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:reaction-role",2,async (instance,params,origin,cancel) => {
const {guild,user,option,overwriteMode} = params const {guild,user,option,overwriteMode} = params
const role = opendiscord.roles.get(option.id) const role = opendiscord.roles.get(option.id)
if (!role) throw new api.ODSystemError("ODAction(ot:reaction-role) => Unknown reaction role (ODRole)") if (!role) throw new api.ODSystemError("ODAction(ot:reaction-role) => Unknown reaction role (ODRole)")
@@ -83,25 +83,25 @@ export const registerActions = async () => {
instance.result = result instance.result = result
await opendiscord.events.get("afterRolesUpdated").emit([user,role]) await opendiscord.events.get("afterRolesUpdated").emit([user,role])
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,user,option,overwriteMode} = params const {guild,user,option,overwriteMode} = params
if (!instance.role || !instance.result) return if (!instance.role || !instance.result) return
//to logs //to logs
if (generalConfig.data.system.logs.enabled && (generalConfig.data.system.messages.reactionRole.logs)){ if (generalConfig.data.logs.enabled && (generalConfig.data.logs.logMessages.reactionRole.logs)){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:reaction-role-logs").build(source,{guild,user,role:instance.role,result:instance.result})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:reaction-role-logs").build(origin,{guild,user,role:instance.role,result:instance.result}))
} }
//to dm //to dm
if (generalConfig.data.system.messages.reactionRole.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:reaction-role-dm").build(source,{guild,user,role:instance.role,result:instance.result})) if (generalConfig.data.logs.logMessages.reactionRole.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:reaction-role-dm").build(origin,{guild,user,role:instance.role,result:instance.result}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,user,option} = params const {guild,user,option} = params
opendiscord.log(user.displayName+" updated his roles!","info",[ opendiscord.log(user.displayName+" updated his roles!","info",[
{key:"user",value:user.username}, {key:"user",value:user.username},
{key:"userid",value:user.id,hidden:true}, {key:"userid",value:user.id,hidden:true},
{key:"method",value:source}, {key:"method",value:origin},
{key:"option",value:option.id.value} {key:"option",value:option.id.value}
]) ])
}) })
+12 -24
View File
@@ -1,15 +1,15 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET REMOVE USER SYSTEM //TICKET REMOVE USER SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:remove-ticket-user")) opendiscord.actions.add(new api.ODAction("opendiscord:remove-ticket-user"))
opendiscord.actions.get("opendiscord:remove-ticket-user").workers.add([ opendiscord.actions.get("opendiscord:remove-ticket-user").workers.add([
new api.ODWorker("opendiscord:remove-ticket-user",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:remove-ticket-user",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params const {guild,channel,user,ticket,reason,data} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to remove user from ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to remove user from ticket! Open Ticket doesn't support threads!")
@@ -29,43 +29,31 @@ export const registerActions = async () => {
opendiscord.log("Failed to remove channel permission overwrites on remove-ticket-user","error") opendiscord.log("Failed to remove channel permission overwrites on remove-ticket-user","error")
} }
//update ticket message //update ticket message (no await)
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket) openticketUtils.updateTicketMessage(guild,channel,user,ticket)
if (ticketMessage){
try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
}catch(e){
opendiscord.log("Unable to edit ticket message on ticket user removal!","error",[
{key:"channel",value:channel.id},
{key:"message",value:ticketMessage.id},
{key:"option",value:ticket.option.id.value}
])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:remove-message").build(source,{guild,channel,user,ticket,reason,data})).message) if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:remove-message").build(origin,{guild,channel,user,ticket,reason,data})).message)
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketUserRemoved").emit([ticket,user,data,channel,reason]) await opendiscord.events.get("afterTicketUserRemoved").emit([ticket,user,data,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params const {guild,channel,user,ticket,reason,data} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.removing.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.removing.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"remove",reason,additionalData:data})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"remove",reason,additionalData:data}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.removing.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"remove",reason,additionalData:data})) if (creator && generalConfig.data.logs.logMessages.removing.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"remove",reason,additionalData:data}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,data} = params const {guild,channel,user,ticket,data} = params
opendiscord.log(user.displayName+" removed "+data.displayName+" from a ticket!","info",[ opendiscord.log(user.displayName+" removed "+data.displayName+" from a ticket!","info",[
@@ -74,7 +62,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
+29 -34
View File
@@ -1,72 +1,67 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET RENAMING SYSTEM //TICKET RENAMING SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:rename-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:rename-ticket"))
opendiscord.actions.get("opendiscord:rename-ticket").workers.add([ opendiscord.actions.get("opendiscord:rename-ticket").workers.add([
new api.ODWorker("opendiscord:rename-ticket",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:rename-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params const {guild,channel,user,ticket,reason,data} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to rename ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to rename ticket! Open Ticket doesn't support threads!")
await opendiscord.events.get("onTicketRename").emit([ticket,user,channel,reason]) await opendiscord.events.get("onTicketRename").emit([ticket,user,channel,reason])
//rename channel (and give error when crashed) //update ticket
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : "" ticket.get("opendiscord:channel-renamed").value = data
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
const originalName = channel.name //calculate channel name
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(data) const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("rename-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
try{ if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
await utilities.timedAwait(channel.setName(newName),2500,(err) => { const originalName = channel.name
opendiscord.log("Failed to rename channel on ticket rename","error") const newName = channelNameResult.newChannelName
})
}catch(err){
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-rename",{guild,channel,user,originalName,newName:data})).message)
}
//update ticket message
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
if (ticketMessage){
try{ try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message) await utilities.timedAwait(channel.setName(newName),2500,(err) => {
}catch(e){ opendiscord.log("Failed to rename channel on ticket rename","error")
opendiscord.log("Unable to edit ticket message on ticket renaming!","error",[ })
{key:"channel",value:"#"+channel.name}, }catch(err){
{key:"channelid",value:channel.id,hidden:true}, opendiscord.log("Unable to rename channel while renaming ticket! Waiting until ratelimit expires...","warning",[
{key:"messageid",value:ticketMessage.id}, {key:"oldName",value:originalName},
{key:"option",value:ticket.option.id.value} {key:"newName",value:newName}
]) ])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException")) const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-rename",{guild,channel,user,originalName,newName})).message)
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
} }
} }
//update ticket message (no await)
openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:rename-message").build(source,{guild,channel,user,ticket,reason,data})).message) if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:rename-message").build(origin,{guild,channel,user,ticket,reason,data})).message)
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketRenamed").emit([ticket,user,channel,reason]) await opendiscord.events.get("afterTicketRenamed").emit([ticket,user,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params const {guild,channel,user,ticket,reason,data} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.renaming.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.renaming.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"rename",reason,additionalData:data})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"rename",reason,additionalData:data}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.renaming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"rename",reason,additionalData:data})) if (creator && generalConfig.data.logs.logMessages.renaming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"rename",reason,additionalData:data}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" renamed a ticket!","info",[ opendiscord.log(user.displayName+" renamed a ticket!","info",[
@@ -75,7 +70,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
+40 -344
View File
@@ -1,15 +1,16 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET REOPENING SYSTEM //TICKET REOPENING SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:reopen-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:reopen-ticket"))
opendiscord.actions.get("opendiscord:reopen-ticket").workers.add([ opendiscord.actions.get("opendiscord:reopen-ticket").workers.add([
new api.ODWorker("opendiscord:reopen-ticket",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:reopen-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to reopen ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to reopen ticket! Open Ticket doesn't support threads!")
@@ -28,65 +29,37 @@ export const registerActions = async () => {
ticket.get("opendiscord:open").value = true ticket.get("opendiscord:open").value = true
ticket.get("opendiscord:busy").value = true ticket.get("opendiscord:busy").value = true
if (generalConfig.data.system.disableAutocloseAfterReopen){ if (generalConfig.data.ticketSystem.disableAutocloseAfterReopen){
//disable autoclose after reopen //disable autoclose after reopen
ticket.get("opendiscord:autoclose-enabled").value = false ticket.get("opendiscord:autoclose-enabled").value = false
ticket.get("opendiscord:autoclose-hours").value = 0 ticket.get("opendiscord:autoclose-hours").value = 0
} }
//update stats //update stats
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-reopened",1,"increase") await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-reopened",1,"increase")
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-reopened",user.id,1,"increase") await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-reopened",user.id,1,"increase")
//update category //calculate & update category
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){ if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
const channelCategory = ticket.option.get("opendiscord:channel-category").value const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("reopen-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
const channelBackupCategory = ticket.option.get("opendiscord:channel-category-backup").value if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
if (channelCategory !== ""){ const originalCategoryName = channel.parent?.name ?? "<unknown>"
//category enabled const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
try { try{
const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory) await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
if (!normalCategory){ process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
//default category was not found })
opendiscord.log("Ticket Reopening Error: Unable to find category! #1","error",[ ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
{key:"categoryid",value:channelCategory}, ticket.get("opendiscord:category").value = categoryResult.newCategoryId
{key:"backup",value:"false"} }catch(err){
]) const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-reopen",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
}else{ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
//default category was found opendiscord.log("Unable to move ticket to reopened category.","error",[
if (normalCategory.children.cache.size >= 49 && channelBackupCategory != ""){
//use backup category
const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelBackupCategory)
if (!backupCategory){
//default category was not found
opendiscord.log("Ticket Reopening Error: Unable to find category! #2","error",[
{key:"categoryid",value:channelBackupCategory},
{key:"backup",value:"true"}
])
}else{
//use backup category
channel.setParent(backupCategory,{lockPermissions:false})
ticket.get("opendiscord:category-mode").value = "backup"
ticket.get("opendiscord:category").value = backupCategory.id
}
}else{
//use default category
channel.setParent(normalCategory,{lockPermissions:false})
ticket.get("opendiscord:category-mode").value = "normal"
ticket.get("opendiscord:category").value = normalCategory.id
}
}
}catch(e){
opendiscord.log("Unable to move ticket to 'reopened category'!","error",[
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
]) ])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
} }
}else{
channel.setParent(null,{lockPermissions:false})
ticket.get("opendiscord:category-mode").value = null
ticket.get("opendiscord:category").value = null
} }
} }
@@ -141,43 +114,38 @@ export const registerActions = async () => {
}) })
channel.permissionOverwrites.set(permissions) channel.permissionOverwrites.set(permissions)
//update ticket message //update ticket message (no await)
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket) openticketUtils.updateTicketMessage(guild,channel,user,ticket)
if (ticketMessage){
try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
}catch(e){
opendiscord.log("Unable to edit ticket message on ticket reopening!","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"messageid",value:ticketMessage.id},
{key:"option",value:ticket.option.id.value}
])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(source,{guild,channel,user,ticket,reason})).message) if (params.sendMessage){
const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(origin,{guild,channel,user,ticket,reason})).message)
if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
messageType:"reopen-message",
messageOrigin:"other",
messageAuthor:user.id,
messageReason:reason
},false)
}
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketReopened").emit([ticket,user,channel,reason]) await opendiscord.events.get("afterTicketReopened").emit([ticket,user,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.reopening.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.reopening.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"reopen",reason,additionalData:null})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"reopen",reason,additionalData:null}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.reopening.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"reopen",reason,additionalData:null})) if (creator && generalConfig.data.logs.logMessages.reopening.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"reopen",reason,additionalData:null}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" reopened a ticket!","info",[ opendiscord.log(user.displayName+" reopened a ticket!","info",[
@@ -186,280 +154,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
} }
export const registerVerifyBars = async () => {
//REOPEN TICKET TICKET MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:reopen-ticket-ticket-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.reopen
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when not closed
if (!ticket.get("opendiscord:closed").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start reopening ticket
if (params.data == "reason"){
//reopen with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
}else{
//reopen without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:reopen-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
}
})
])
opendiscord.verifybars.get("opendiscord:reopen-ticket-ticket-message").failure.add([
new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
})
])
//REOPEN TICKET CLOSE MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket-close-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-close-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:reopen-ticket-close-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.reopen
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when not closed
if (!ticket.get("opendiscord:closed").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start reopening ticket
if (params.data == "reason"){
//reopen with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("close-message",{guild,channel,user,ticket}))
}else{
//reopen without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:reopen-ticket").run("close-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("close-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:reopen-ticket-close-message").failure.add([
new api.ODWorker("opendiscord:back-to-close-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason}))
})
])
//REOPEN TICKET AUTOCLOSE MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket-autoclose-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-autoclose-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:reopen-ticket-autoclose-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.reopen
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when not closed
if (!ticket.get("opendiscord:closed").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start reopening ticket
if (params.data == "reason"){
//reopen with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("autoclose-message",{guild,channel,user,ticket}))
}else{
//reopen without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:reopen-ticket").run("autoclose-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("autoclose-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:reopen-ticket-autoclose-message").failure.add([
new api.ODWorker("opendiscord:back-to-autoclose-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("other",{guild,channel,user,ticket}))
})
])
opendiscord.actions.get("opendiscord:reopen-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => {
//set busy to false in case of crash or cancel
params.ticket.get("opendiscord:busy").value = false
})
}
+26 -38
View File
@@ -1,15 +1,15 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET TRANSFER SYSTEM //TICKET TRANSFER SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:transfer-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:transfer-ticket"))
opendiscord.actions.get("opendiscord:transfer-ticket").workers.add([ opendiscord.actions.get("opendiscord:transfer-ticket").workers.add([
new api.ODWorker("opendiscord:transfer-ticket",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:transfer-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,newCreator} = params const {guild,channel,user,ticket,reason,newCreator} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to transfer ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to transfer ticket! Open Ticket doesn't support threads!")
@@ -33,12 +33,8 @@ export const registerActions = async () => {
} }
//update stats //update stats
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-transferred",1,"increase") await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-transferred",1,"increase")
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-transferred",user.id,1,"increase") await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-transferred",user.id,1,"increase")
//get new channel properties
const channelPrefix = ticket.option.get("opendiscord:channel-prefix").value
const channelSuffix = ticket.get("opendiscord:channel-suffix").value
//handle permissions //handle permissions
const permissions: discord.OverwriteResolvable[] = [{ const permissions: discord.OverwriteResolvable[] = [{
@@ -93,48 +89,40 @@ export const registerActions = async () => {
opendiscord.log("Failed to reset channel permissions on ticket transfer!","error") opendiscord.log("Failed to reset channel permissions on ticket transfer!","error")
} }
//rename channel (and give error when crashed) //calculate channel name
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : "" const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("transfer-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? "" if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
const originalName = channel.name
const originalName = channel.name const newName = channelNameResult.newChannelName
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channelPrefix+channelSuffix)
try{
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
opendiscord.log("Failed to rename channel on ticket transfer","error")
})
}catch(err){
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-transfer",{guild,channel,user,originalName,newName:newName})).message)
}
//update ticket message
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
if (ticketMessage){
try{ try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message) await utilities.timedAwait(channel.setName(newName),2500,(err) => {
}catch(e){ opendiscord.log("Failed to rename channel on ticket transfer","error")
opendiscord.log("Unable to edit ticket message on ticket transferring!","error",[ })
{key:"channel",value:"#"+channel.name}, }catch(err){
{key:"channelid",value:channel.id,hidden:true}, opendiscord.log("Unable to rename channel while transferring ticket! Waiting until ratelimit expires...","warning",[
{key:"messageid",value:ticketMessage.id}, {key:"oldName",value:originalName},
{key:"option",value:ticket.option.id.value} {key:"newName",value:newName}
]) ])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException")) const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-transfer",{guild,channel,user,originalName,newName})).message)
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
} }
} }
//update ticket message (no await)
openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:transfer-message").build(source,{guild,channel,user,ticket,oldCreator,newCreator,reason})).message) if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:transfer-message").build(origin,{guild,channel,user,ticket,oldCreator,newCreator,reason})).message)
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketTransferred").emit([ticket,user,channel,oldCreator,newCreator,reason]) await opendiscord.events.get("afterTicketTransferred").emit([ticket,user,channel,oldCreator,newCreator,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newCreator,reason} = params const {guild,channel,user,ticket,newCreator,reason} = params
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newCreator} = params const {guild,channel,user,ticket,newCreator} = params
opendiscord.log(user.displayName+" transferred a ticket to '"+newCreator.displayName+"'!","info",[ opendiscord.log(user.displayName+" transferred a ticket to '"+newCreator.displayName+"'!","info",[
@@ -143,7 +131,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
+38 -255
View File
@@ -1,15 +1,16 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET UNCLAIMING SYSTEM //TICKET UNCLAIMING SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:unclaim-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:unclaim-ticket"))
opendiscord.actions.get("opendiscord:unclaim-ticket").workers.add([ opendiscord.actions.get("opendiscord:unclaim-ticket").workers.add([
new api.ODWorker("opendiscord:unclaim-ticket",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:unclaim-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to unclaim ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to unclaim ticket! Open Ticket doesn't support threads!")
@@ -21,97 +22,63 @@ export const registerActions = async () => {
ticket.get("opendiscord:claimed-on").value = null ticket.get("opendiscord:claimed-on").value = null
ticket.get("opendiscord:busy").value = true ticket.get("opendiscord:busy").value = true
//update category //calculate & update category
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){ if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
const channelCategory = ticket.option.get("opendiscord:channel-category").value const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("unclaim-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
const channelBackupCategory = ticket.option.get("opendiscord:channel-category-backup").value if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
if (channelCategory !== ""){ const originalCategoryName = channel.parent?.name ?? "<unknown>"
//category enabled const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
try { try{
const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory) await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
if (!normalCategory){ process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
//default category was not found })
opendiscord.log("Ticket Unclaiming Error: Unable to find category! #1","error",[ ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
{key:"categoryid",value:channelCategory}, ticket.get("opendiscord:category").value = categoryResult.newCategoryId
{key:"backup",value:"false"} }catch(err){
]) const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-unclaim",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
}else{ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
//default category was found opendiscord.log("Unable to move ticket to unclaimed category.","error",[
if (normalCategory.children.cache.size >= 49 && channelBackupCategory != ""){
//use backup category
const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelBackupCategory)
if (!backupCategory){
//default category was not found
opendiscord.log("Ticket Unclaiming Error: Unable to find category! #2","error",[
{key:"categoryid",value:channelBackupCategory},
{key:"backup",value:"true"}
])
}else{
//use backup category
channel.setParent(backupCategory,{lockPermissions:false})
ticket.get("opendiscord:category-mode").value = "backup"
ticket.get("opendiscord:category").value = backupCategory.id
}
}else{
//use default category
channel.setParent(normalCategory,{lockPermissions:false})
ticket.get("opendiscord:category-mode").value = "normal"
ticket.get("opendiscord:category").value = normalCategory.id
}
}
}catch(e){
opendiscord.log("Unable to move ticket to 'unclaimed category'!","error",[
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true} {key:"channelid",value:channel.id,hidden:true},
{key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
]) ])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
} }
}else{
channel.setParent(null,{lockPermissions:false})
ticket.get("opendiscord:category-mode").value = null
ticket.get("opendiscord:category").value = null
} }
} }
//update ticket message //update ticket message (no await)
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket) openticketUtils.updateTicketMessage(guild,channel,user,ticket)
if (ticketMessage){
try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
}catch(e){
opendiscord.log("Unable to edit ticket message on ticket unclaiming!","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"messageid",value:ticketMessage.id},
{key:"option",value:ticket.option.id.value}
])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(source,{guild,channel,user,ticket,reason})).message) if (params.sendMessage){
const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(origin,{guild,channel,user,ticket,reason})).message)
if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
messageType:"unclaim-message",
messageOrigin:"other",
messageAuthor:user.id,
messageReason:reason
},false)
}
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketUnclaimed").emit([ticket,user,channel,reason]) await opendiscord.events.get("afterTicketUnclaimed").emit([ticket,user,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.claiming.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.claiming.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"unclaim",reason,additionalData:null})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"unclaim",reason,additionalData:null}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.claiming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"unclaim",reason,additionalData:null})) if (creator && generalConfig.data.logs.logMessages.claiming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"unclaim",reason,additionalData:null}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" unclaimed a ticket!","info",[ opendiscord.log(user.displayName+" unclaimed a ticket!","info",[
@@ -120,192 +87,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
} }
export const registerVerifyBars = async () => {
//UNCLAIM TICKET TICKET MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unclaim-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:unclaim-ticket-ticket-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.unclaim
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when not claimed
if (!ticket.get("opendiscord:claimed").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start unclaiming ticket
if (params.data == "reason"){
//unclaim with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unclaim-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
}else{
//unclaim without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:unclaim-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
}
})
])
opendiscord.verifybars.get("opendiscord:unclaim-ticket-ticket-message").failure.add([
new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
})
])
//UNCLAIM TICKET CLAIM MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unclaim-ticket-claim-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-claim-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:unclaim-ticket-claim-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.unclaim
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when not claimed
if (!ticket.get("opendiscord:claimed").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start unclaiming ticket
if (params.data == "reason"){
//unclaim with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unclaim-ticket-reason").build("claim-message",{guild,channel,user,ticket}))
}else{
//unclaim without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:unclaim-ticket").run("claim-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("claim-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:unclaim-ticket-claim-message").failure.add([
new api.ODWorker("opendiscord:back-to-claim-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("other",{guild,channel,user,ticket,reason}))
})
])
opendiscord.actions.get("opendiscord:unclaim-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => {
//set busy to false in case of crash or cancel
params.ticket.get("opendiscord:busy").value = false
})
}
+36 -219
View File
@@ -1,15 +1,16 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET UNPINNING SYSTEM //TICKET UNPINNING SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:unpin-ticket")) opendiscord.actions.add(new api.ODAction("opendiscord:unpin-ticket"))
opendiscord.actions.get("opendiscord:unpin-ticket").workers.add([ opendiscord.actions.get("opendiscord:unpin-ticket").workers.add([
new api.ODWorker("opendiscord:unpin-ticket",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:unpin-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to unpin ticket! Open Ticket doesn't support threads!") if (channel.isThread()) throw new api.ODSystemError("Unable to unpin ticket! Open Ticket doesn't support threads!")
@@ -21,58 +22,58 @@ export const registerActions = async () => {
ticket.get("opendiscord:pinned-on").value = null ticket.get("opendiscord:pinned-on").value = null
ticket.get("opendiscord:busy").value = true ticket.get("opendiscord:busy").value = true
//rename channel (and give error when crashed) //calculate channel name
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : "" const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("unpin-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? "" if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
const originalName = channel.name
const originalName = channel.name const newName = channelNameResult.newChannelName
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channel.name)
try{
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
opendiscord.log("Failed to rename channel on ticket unpin","error")
})
}catch(err){
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-unpin",{guild,channel,user,originalName,newName})).message)
}
//update ticket message
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
if (ticketMessage){
try{ try{
ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message) await utilities.timedAwait(channel.setName(newName),2500,(err) => {
}catch(e){ opendiscord.log("Failed to rename channel on ticket unpin","error")
opendiscord.log("Unable to edit ticket message on ticket unpinning!","error",[ })
{key:"channel",value:"#"+channel.name}, }catch(err){
{key:"channelid",value:channel.id,hidden:true}, opendiscord.log("Unable to rename channel while unpinning ticket! Waiting until ratelimit expires...","warning",[
{key:"messageid",value:ticketMessage.id}, {key:"oldName",value:originalName},
{key:"option",value:ticket.option.id.value} {key:"newName",value:newName}
]) ])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException")) const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-unpin",{guild,channel,user,originalName,newName})).message)
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
} }
} }
//update ticket message (no await)
openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(source,{guild,channel,user,ticket,reason})).message) if (params.sendMessage){
const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(origin,{guild,channel,user,ticket,reason})).message)
if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
messageType:"unpin-message",
messageOrigin:"other",
messageAuthor:user.id,
messageReason:reason
},false)
}
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketUnpinned").emit([ticket,user,channel,reason]) await opendiscord.events.get("afterTicketUnpinned").emit([ticket,user,channel,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params const {guild,channel,user,ticket,reason} = params
//to logs //to logs
if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.pinning.logs){ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.pinning.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs") const logChannel = opendiscord.posts.get("opendiscord:logs")
if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"unpin",reason,additionalData:null})) if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"unpin",reason,additionalData:null}))
} }
//to dm //to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator") const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
if (creator && generalConfig.data.system.messages.pinning.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"unpin",reason,additionalData:null})) if (creator && generalConfig.data.logs.logMessages.pinning.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"unpin",reason,additionalData:null}))
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" unpinned a ticket!","info",[ opendiscord.log(user.displayName+" unpinned a ticket!","info",[
@@ -81,192 +82,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"}, {key:"reason",value:params.reason ?? "/"},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
} }
export const registerVerifyBars = async () => {
//UNPIN TICKET TICKET MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unpin-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:unpin-ticket-ticket-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.unpin
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when not pinned
if (!ticket.get("opendiscord:pinned").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start unpining ticket
if (params.data == "reason"){
//unpin with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unpin-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
}else{
//unpin without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:unpin-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
}
})
])
opendiscord.verifybars.get("opendiscord:unpin-ticket-ticket-message").failure.add([
new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
})
])
//UNPIN TICKET PIN MESSAGE
opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unpin-ticket-pin-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-pin-message"),!generalConfig.data.system.disableVerifyBars))
opendiscord.verifybars.get("opendiscord:unpin-ticket-pin-message").success.add([
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
const permissionMode = generalConfig.data.system.permissions.unpin
if (permissionMode == "none"){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else if (permissionMode == "everyone") return
else if (permissionMode == "admin"){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
}else return
}else{
if (!instance.guild || !instance.member){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
return cancel()
}
const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
if (!role){
//error
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
return cancel()
}
if (!role.members.has(instance.member.id)){
//no permissions
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
return cancel()
}else return
}
}),
new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
//return when not pinned
if (!ticket.get("opendiscord:pinned").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"}))
return cancel()
}
//return when busy
if (ticket.get("opendiscord:busy").value){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
return cancel()
}
//start unpinning ticket
if (params.data == "reason"){
//unpin with reason
instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unpin-ticket-reason").build("pin-message",{guild,channel,user,ticket}))
}else{
//unpin without reason
await instance.defer("update",false)
await opendiscord.actions.get("opendiscord:unpin-ticket").run("pin-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("pin-message",{guild,channel,user,ticket,reason:null}))
}
})
])
opendiscord.verifybars.get("opendiscord:unpin-ticket-pin-message").failure.add([
new api.ODWorker("opendiscord:back-to-pin-message",0,async (instance,params,source,cancel) => {
const {guild,channel,user} = instance
const {verifybarMessage} = params
if (!guild){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
return cancel()
}
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
return cancel()
}
const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("other",{guild,channel,user,ticket,reason}))
})
])
opendiscord.actions.get("opendiscord:unpin-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => {
//set busy to false in case of crash or cancel
params.ticket.get("opendiscord:busy").value = false
})
}
+24 -19
View File
@@ -1,15 +1,15 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET TOPIC SYSTEM //TICKET TOPIC SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:update-ticket-priority")) opendiscord.actions.add(new api.ODAction("opendiscord:update-ticket-priority"))
opendiscord.actions.get("opendiscord:update-ticket-priority").workers.add([ opendiscord.actions.get("opendiscord:update-ticket-priority").workers.add([
new api.ODWorker("opendiscord:update-ticket-priority",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:update-ticket-priority",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newPriority,reason} = params const {guild,channel,user,ticket,newPriority,reason} = params
if (channel.isThread() || !(channel instanceof discord.TextChannel)) throw new api.ODSystemError("Unable to set priority of ticket! Open Ticket doesn't support threads!") if (channel.isThread() || !(channel instanceof discord.TextChannel)) throw new api.ODSystemError("Unable to set priority of ticket! Open Ticket doesn't support threads!")
@@ -20,32 +20,37 @@ export const registerActions = async () => {
ticket.get("opendiscord:busy").value = true ticket.get("opendiscord:busy").value = true
if (newPriority) ticket.get("opendiscord:priority").value = newPriority.priority if (newPriority) ticket.get("opendiscord:priority").value = newPriority.priority
//rename channel (and give error when crashed) //calculate channel name
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : "" const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("priority-change",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
const priorityEmoji = newPriority.channelEmoji ?? "" if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
const originalName = channel.name
const originalName = channel.name const newName = channelNameResult.newChannelName
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channel.name) try{
try{ await utilities.timedAwait(channel.setName(newName),2500,(err) => {
await utilities.timedAwait(channel.setName(newName),2500,(err) => { opendiscord.log("Failed to rename channel on priority change","error")
opendiscord.log("Failed to rename channel on ticket priority update","error") })
}) }catch(err){
}catch(err){ opendiscord.log("Unable to rename channel while updating ticket priority! Waiting until ratelimit expires...","warning",[
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-priority",{guild,channel,user,originalName,newName})).message) {key:"oldName",value:originalName},
{key:"newName",value:newName}
])
const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-priority",{guild,channel,user,originalName,newName})).message)
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
}
} }
//reply with new message //reply with new message
if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:priority-set").build(source,{guild,channel,user,ticket,priority:newPriority,reason})).message) if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:priority-set").build(origin,{guild,channel,user,ticket,priority:newPriority,reason})).message)
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketPriorityChanged").emit([ticket,user,channel,oldPriority,newPriority,reason]) await opendiscord.events.get("afterTicketPriorityChanged").emit([ticket,user,channel,oldPriority,newPriority,reason])
//update channel topic //update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null}) await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newPriority} = params const {guild,channel,user,ticket,newPriority} = params
opendiscord.log(user.displayName+" changed the priority of a ticket!","info",[ opendiscord.log(user.displayName+" changed the priority of a ticket!","info",[
@@ -54,7 +59,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"priority",value:newPriority.id.value}, {key:"priority",value:newPriority.id.value},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
+16 -16
View File
@@ -1,16 +1,16 @@
/////////////////////////////////////// ///////////////////////////////////////
//TICKET TOPIC SYSTEM //TICKET TOPIC SYSTEM
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages const lang = opendiscord.languages
export const registerActions = async () => { export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:update-ticket-topic")) opendiscord.actions.add(new api.ODAction("opendiscord:update-ticket-topic"))
opendiscord.actions.get("opendiscord:update-ticket-topic").workers.add([ opendiscord.actions.get("opendiscord:update-ticket-topic").workers.add([
new api.ODWorker("opendiscord:update-ticket-topic",2,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:update-ticket-topic",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newTopic} = params const {guild,channel,user,ticket,newTopic} = params
if (channel.isThread() || !(channel instanceof discord.TextChannel)) throw new api.ODSystemError("Unable to set topic of ticket! Open Ticket doesn't support threads!") if (channel.isThread() || !(channel instanceof discord.TextChannel)) throw new api.ODSystemError("Unable to set topic of ticket! Open Ticket doesn't support threads!")
@@ -29,28 +29,28 @@ export const registerActions = async () => {
//handle channel topic //handle channel topic
const channelTopics: string[] = [] const channelTopics: string[] = []
if (generalConfig.data.system.channelTopic.showOptionName) channelTopics.push(ticket.option.get("opendiscord:name").value) if (generalConfig.data.ticketSystem.channelTopic.showOptionName) channelTopics.push(ticket.option.get("opendiscord:name").value)
if (generalConfig.data.system.channelTopic.showOptionDescription) channelTopics.push(ticket.option.get("opendiscord:description").value) if (generalConfig.data.ticketSystem.channelTopic.showOptionDescription) channelTopics.push(ticket.option.get("opendiscord:description").value)
if (generalConfig.data.system.channelTopic.showOptionTopic) channelTopics.push(ticket.get("opendiscord:topic").value) if (generalConfig.data.ticketSystem.channelTopic.showOptionTopic) channelTopics.push(ticket.get("opendiscord:topic").value)
if (generalConfig.data.system.channelTopic.showPriority) channelTopics.push("**"+lang.getTranslation("params.uppercase.priority")+":** "+opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).renderDisplayName()) if (generalConfig.data.ticketSystem.channelTopic.showPriority) channelTopics.push("**"+lang.getTranslation("params.uppercase.priority")+":** "+opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).renderDisplayName())
if (generalConfig.data.system.channelTopic.showClosed) channelTopics.push("**"+lang.getTranslation("params.uppercase.status")+":** "+(closed ? lang.getTranslation("params.uppercase.closed") : lang.getTranslation("params.uppercase.open"))) if (generalConfig.data.ticketSystem.channelTopic.showClosed) channelTopics.push("**"+lang.getTranslation("params.uppercase.status")+":** "+(closed ? lang.getTranslation("params.uppercase.closed") : lang.getTranslation("params.uppercase.open")))
if (generalConfig.data.system.channelTopic.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+(claimedBy ? discord.userMention(claimedBy) : lang.getTranslation("params.uppercase.noone"))) if (generalConfig.data.ticketSystem.channelTopic.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+(claimedBy ? discord.userMention(claimedBy) : lang.getTranslation("params.uppercase.noone")))
if (generalConfig.data.system.channelTopic.showPinned) channelTopics.push("**"+lang.getTranslation("params.uppercase.pinned")+":** "+(pinned ? lang.getTranslation("params.uppercase.yes") : lang.getTranslation("params.uppercase.no"))) if (generalConfig.data.ticketSystem.channelTopic.showPinned) channelTopics.push("**"+lang.getTranslation("params.uppercase.pinned")+":** "+(pinned ? lang.getTranslation("params.uppercase.yes") : lang.getTranslation("params.uppercase.no")))
if (generalConfig.data.system.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(creator)) if (generalConfig.data.ticketSystem.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(creator))
if (generalConfig.data.system.channelTopic.showParticipants) channelTopics.push("**"+lang.getTranslation("params.uppercase.participants")+":** "+ticket.get("opendiscord:participants").value.map((p) => (p.type == "user") ? discord.userMention(p.id) : discord.roleMention(p.id)).join(", ")) if (generalConfig.data.ticketSystem.channelTopic.showParticipants) channelTopics.push("**"+lang.getTranslation("params.uppercase.participants")+":** "+ticket.get("opendiscord:participants").value.map((p) => (p.type == "user") ? discord.userMention(p.id) : discord.roleMention(p.id)).join(", "))
//update channel //update channel
channel.setTopic(channelTopics.join(" • "),"Topic Changed") channel.setTopic(channelTopics.join(" • "),"Topic Changed")
//reply with new message //reply with new message
if (params.sendMessage && newTopic) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:topic-set").build(source,{guild,channel,user,ticket,topic:newTopic})).message) if (params.sendMessage && newTopic) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:topic-set").build(origin,{guild,channel,user,ticket,topic:newTopic})).message)
ticket.get("opendiscord:busy").value = false ticket.get("opendiscord:busy").value = false
if (newTopic) await opendiscord.events.get("afterTicketTopicChanged").emit([ticket,user,channel,oldTopic,newTopic]) if (newTopic) await opendiscord.events.get("afterTicketTopicChanged").emit([ticket,user,channel,oldTopic,newTopic])
}), }),
new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => { new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params const {guild,channel,user,ticket} = params
}), }),
new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => { new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newTopic} = params const {guild,channel,user,ticket,newTopic} = params
if (newTopic) opendiscord.log(user.displayName+" changed the topic of a ticket!","info",[ if (newTopic) opendiscord.log(user.displayName+" changed the topic of a ticket!","info",[
@@ -59,7 +59,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name}, {key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true}, {key:"channelid",value:channel.id,hidden:true},
{key:"topic",value:newTopic}, {key:"topic",value:newTopic},
{key:"method",value:source} {key:"method",value:origin}
]) ])
}) })
]) ])
+176
View File
@@ -0,0 +1,176 @@
///////////////////////////////////////
//OPEN TICKET UTILITY FUNCTIONS
///////////////////////////////////////
import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js"
/**Fetch the interactive message state. If not present, auto replies with error and returns `null`. When `null` is received, the worker should be returned and canceled. */
export async function replyInteractiveMessageState(instance:api.ODButtonResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",channel:discord.TextBasedChannel,message:discord.Message|null,replacementCommandName:string){
//check message state
const {user,member,guild} = instance
const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
if (!message){
//TODO TRANSLATION!!!
await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"Unable to locate message of interaction. Use the command `{0}` instead.".replace("{0}",replacementCommandName),layout:"simple",customTitle:"Message State Error"}))
return null
}
const state = await interactiveMsgState.getMsgState({channel,message})
if (!state){
//TODO TRANSLATION!!!
await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This interaction is no longer valid or has expired. Use the command `{0}` instead. It is normal to receive this error after a major Open Ticket update.".replace("{0}",replacementCommandName),layout:"simple",customTitle:"Message State Expired"}))
return null
}else return state
}
/**Check the permissions for this command. If not allowed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyHasPermissions(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",commandName:keyof api.ODGeneralJsonConfig_SystemPermissions,settings?:api.ODPermissionSettings) {
//check permissions
const {user,member,channel,guild} = instance
const generalConfig = opendiscord.configs.get("opendiscord:general")
const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.permissions[commandName],"support",user,member,channel,guild,settings)
if (!permsResult.hasPerms){
if (permsResult.reason == "not-in-server" && channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
else if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]}))
return false
}else return true
}
/**Check if channel is in guild/server. If not, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyIsInGuild(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other"){
//check is in guild/server
const {user,member,channel,guild} = instance
if (!guild){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user}))
return false
}else return true
}
/**Check if channel is valid ticket. If not, auto replies with error and returns `null`. When `null` is received, the worker should be returned and canceled. */
export async function replyIsTicket(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other") {
//check if ticket exists
const {user,member,channel,guild} = instance
if (!channel) return null
const ticket = opendiscord.tickets.get(channel.id)
if (!ticket || channel.isDMBased()){
await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build(origin,{guild,channel,user}))
return null
}else return ticket
}
/**Check if ticket is not busy and available. If not, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyTicketIsAvailable(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
//return when busy
const {user,member,channel,guild} = instance
if (ticket.get("opendiscord:busy").value){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build(origin,{guild,channel,user}))
return false
}else return true
}
/**Check if ticket is open. If closed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyTicketMustBeOpen(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket){
//return when already closed
const {user,member,channel,guild} = instance
if (ticket.get("opendiscord:closed").value){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.close"),layout:"simple"}))
return false
}else return true
}
/**Check if ticket is closed. If open, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyTicketMustBeClosed(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
//return when already open
const {user,member,channel,guild} = instance
if (!ticket.get("opendiscord:closed").value){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"}))
return false
}else return true
}
/**Check if ticket is unclaimed. If claimed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyTicketMustBeUnclaimed(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
//return when already claimed
const {user,member,channel,guild} = instance
if (ticket.get("opendiscord:claimed").value){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"}))
return false
}else return true
}
/**Check if ticket is claimed. If unclaimed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyTicketMustBeClaimed(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
//return when already unclaimed
const {user,member,channel,guild} = instance
if (!ticket.get("opendiscord:claimed").value){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"}))
return false
}else return true
}
/**Check if ticket is unpinned. If pinned, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyTicketMustBeUnpinned(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
//return when already pinned
const {user,member,channel,guild} = instance
if (ticket.get("opendiscord:pinned").value){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"}))
return false
}else return true
}
/**Check if ticket is pinned. If unpinned, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyTicketMustBePinned(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
//return when already unpinned
const {user,member,channel,guild} = instance
if (!ticket.get("opendiscord:pinned").value){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"}))
return false
}else return true
}
/**Check if the ticket can be closed/deleted before a message has been sent by an admin or user. If not passing the test, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
export async function replyMessageMustBeSentBeforeClose(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket,commandName:keyof api.ODGeneralJsonConfig_SystemPermissions) {
//return when not allowed because of missing messages
const {user,member,channel,guild} = instance
const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages
const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.permissions[commandName],"support",user,member,channel,guild)
if (!permsResult.hasPerms) throw new api.ODSystemError("Please check permissions before using replyMessageMustBeSentBeforeClose()")
if (!guild || channel.isDMBased()) throw new api.ODSystemError("replyMessageMustBeSentBeforeClose() must be used in a guild and not a DM channel.")
if (!permsResult.isAdmin && (!generalConfig.data.ticketSystem.allowCloseBeforeMessage || !generalConfig.data.ticketSystem.allowCloseBeforeAdminMessage)){
const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
if (analysis && !generalConfig.data.ticketSystem.allowCloseBeforeMessage && analysis.totalMessages < 1){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return false
}
if (analysis && !generalConfig.data.ticketSystem.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
return false
}
return true
}else return true
}
/**Update the ticket message from a given ticket channel. This should be used after every change to the `ODTicket` after an action. */
export async function updateTicketMessage(guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:api.ODTicket){
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
if (!ticketMessage || !user || !channel || !guild || channel.isDMBased()) return
try{
await ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
}catch(e){
opendiscord.log("Unable to edit ticket message!","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"messageid",value:ticketMessage.id},
{key:"option",value:ticket.option.id.value}
])
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
+49 -70
View File
@@ -1,15 +1,37 @@
/////////////////////////////////////// ///////////////////////////////////////
//BUTTON BUILDERS //BUTTON BUILDERS
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const buttons = opendiscord.builders.buttons const buttons = opendiscord.builders.buttons
const lang = opendiscord.languages const lang = opendiscord.languages
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerAllButtons = async () => { export async function registerAllButtons(){
verifybarButtons() //VERIFYBAR BUTTON
buttons.add(new api.ODButton("opendiscord:verifybar-button"))
buttons.get("opendiscord:verifybar-button").workers.add(
new api.ODWorker("opendiscord:verifybar-button",0,async (instance,params) => {
const {verifybar,verifyButtonId} = params
if (params.verifyButtonId.length > 40) throw new api.ODSystemError("ODButton:opendiscord:verifybar-button => verifyButtonId '"+verifyButtonId+"' exceeds 40 characters limit!")
const color = ("customColor" in params && params.customColor) ? params.customColor : "gray"
//TODO TRANSLATION!!!
const defaultLabel = (params.defaultButtonType == "✅") ? "Accept" : "Cancel"
const defaultEmoji = (params.defaultButtonType == "✅") ? "✅" : "❌"
const label = ("customLabel" in params && params.customLabel) ? params.customLabel : (params.useDefaultLabels ? defaultLabel : null)
const emoji = ("customEmoji" in params && params.customEmoji) ? params.customEmoji : defaultEmoji
instance.setCustomId("od:verifybar|"+verifybar.id.value+"|"+verifyButtonId)
instance.setMode("button")
instance.setColor(color)
if (label) instance.setLabel(label)
if (emoji) instance.setEmoji(emoji)
})
)
errorButtons() errorButtons()
helpMenuButtons() helpMenuButtons()
panelButtons() panelButtons()
@@ -18,50 +40,6 @@ export const registerAllButtons = async () => {
clearButtons() clearButtons()
} }
const verifybarButtons = () => {
//VERIFYBAR SUCCESS
buttons.add(new api.ODButton("opendiscord:verifybar-success"))
buttons.get("opendiscord:verifybar-success").workers.add(
new api.ODWorker("opendiscord:verifybar-success",0,async (instance,params) => {
const {verifybar,customData,customColor,customLabel,customEmoji} = params
if (customData && customData.length > 40) throw new api.ODSystemError("ODButton:opendiscord:verifybar-success => customData exceeds 40 characters limit!")
const newData = (customData) ? "_"+customData : ""
const newColor = customColor ?? "gray"
const newLabel = customLabel ?? ""
const newEmoji = customEmoji ?? "✅"
instance.setCustomId("od:verifybar-success_"+verifybar.id.value+newData)
instance.setMode("button")
instance.setColor(newColor)
if (newLabel) instance.setLabel(newLabel)
if (newEmoji) instance.setEmoji(newEmoji)
})
)
//VERIFYBAR FAILURE
buttons.add(new api.ODButton("opendiscord:verifybar-failure"))
buttons.get("opendiscord:verifybar-failure").workers.add(
new api.ODWorker("opendiscord:verifybar-failure",0,async (instance,params) => {
const {verifybar,customData,customColor,customLabel,customEmoji} = params
if (customData && customData.length > 40) throw new api.ODSystemError("ODButton:opendiscord:verifybar-success => customData exceeds 40 characters limit!")
const newData = (customData) ? "_"+customData : ""
const newColor = customColor ?? "gray"
const newLabel = customLabel ?? ""
const newEmoji = customEmoji ?? "❌"
instance.setCustomId("od:verifybar-failure_"+verifybar.id.value+newData)
instance.setMode("button")
instance.setColor(newColor)
if (newLabel) instance.setLabel(newLabel)
if (newEmoji) instance.setEmoji(newEmoji)
})
)
}
const errorButtons = () => { const errorButtons = () => {
//ERROR TICKET DEPRECATED TRANSCRIPT //ERROR TICKET DEPRECATED TRANSCRIPT
buttons.add(new api.ODButton("opendiscord:error-ticket-deprecated-transcript")) buttons.add(new api.ODButton("opendiscord:error-ticket-deprecated-transcript"))
@@ -201,11 +179,11 @@ const ticketButtons = () => {
//CLOSE TICKET //CLOSE TICKET
buttons.add(new api.ODButton("opendiscord:close-ticket")) buttons.add(new api.ODButton("opendiscord:close-ticket"))
buttons.get("opendiscord:close-ticket").workers.add( buttons.get("opendiscord:close-ticket").workers.add(
new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,source) => { new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params const {guild,channel,ticket} = params
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:close-ticket_"+source) instance.setCustomId("od:close-ticket")
instance.setColor("gray") instance.setColor("gray")
instance.setEmoji("🔒") instance.setEmoji("🔒")
instance.setLabel(lang.getTranslation("actions.buttons.close")) instance.setLabel(lang.getTranslation("actions.buttons.close"))
@@ -215,11 +193,11 @@ const ticketButtons = () => {
//DELETE TICKET //DELETE TICKET
buttons.add(new api.ODButton("opendiscord:delete-ticket")) buttons.add(new api.ODButton("opendiscord:delete-ticket"))
buttons.get("opendiscord:delete-ticket").workers.add( buttons.get("opendiscord:delete-ticket").workers.add(
new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source) => { new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params const {guild,channel,ticket} = params
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:delete-ticket_"+source) instance.setCustomId("od:delete-ticket")
instance.setColor("red") instance.setColor("red")
instance.setEmoji("✖") instance.setEmoji("✖")
instance.setLabel(lang.getTranslation("actions.buttons.delete")) instance.setLabel(lang.getTranslation("actions.buttons.delete"))
@@ -229,11 +207,11 @@ const ticketButtons = () => {
//REOPEN TICKET //REOPEN TICKET
buttons.add(new api.ODButton("opendiscord:reopen-ticket")) buttons.add(new api.ODButton("opendiscord:reopen-ticket"))
buttons.get("opendiscord:reopen-ticket").workers.add( buttons.get("opendiscord:reopen-ticket").workers.add(
new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,source) => { new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params const {guild,channel,ticket} = params
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:reopen-ticket_"+source) instance.setCustomId("od:reopen-ticket")
instance.setColor("green") instance.setColor("green")
instance.setEmoji("🔓") instance.setEmoji("🔓")
instance.setLabel(lang.getTranslation("actions.buttons.reopen")) instance.setLabel(lang.getTranslation("actions.buttons.reopen"))
@@ -243,11 +221,11 @@ const ticketButtons = () => {
//CLAIM TICKET //CLAIM TICKET
buttons.add(new api.ODButton("opendiscord:claim-ticket")) buttons.add(new api.ODButton("opendiscord:claim-ticket"))
buttons.get("opendiscord:claim-ticket").workers.add( buttons.get("opendiscord:claim-ticket").workers.add(
new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,source) => { new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params const {guild,channel,ticket} = params
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:claim-ticket_"+source) instance.setCustomId("od:claim-ticket")
instance.setColor("green") instance.setColor("green")
instance.setEmoji("👋") instance.setEmoji("👋")
instance.setLabel(lang.getTranslation("actions.buttons.claim")) instance.setLabel(lang.getTranslation("actions.buttons.claim"))
@@ -257,11 +235,11 @@ const ticketButtons = () => {
//UNCLAIM TICKET //UNCLAIM TICKET
buttons.add(new api.ODButton("opendiscord:unclaim-ticket")) buttons.add(new api.ODButton("opendiscord:unclaim-ticket"))
buttons.get("opendiscord:unclaim-ticket").workers.add( buttons.get("opendiscord:unclaim-ticket").workers.add(
new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,source) => { new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params const {guild,channel,ticket} = params
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:unclaim-ticket_"+source) instance.setCustomId("od:unclaim-ticket")
instance.setColor("green") instance.setColor("green")
instance.setEmoji("↩️") instance.setEmoji("↩️")
instance.setLabel(lang.getTranslation("actions.buttons.unclaim")) instance.setLabel(lang.getTranslation("actions.buttons.unclaim"))
@@ -271,13 +249,13 @@ const ticketButtons = () => {
//PIN TICKET //PIN TICKET
buttons.add(new api.ODButton("opendiscord:pin-ticket")) buttons.add(new api.ODButton("opendiscord:pin-ticket"))
buttons.get("opendiscord:pin-ticket").workers.add( buttons.get("opendiscord:pin-ticket").workers.add(
new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,source) => { new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params const {guild,channel,ticket} = params
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:pin-ticket_"+source) instance.setCustomId("od:pin-ticket")
instance.setColor("gray") instance.setColor("gray")
instance.setEmoji(generalConfig.data.system.pinEmoji) instance.setEmoji(generalConfig.data.ticketSystem.pinEmoji)
instance.setLabel(lang.getTranslation("actions.buttons.pin")) instance.setLabel(lang.getTranslation("actions.buttons.pin"))
}) })
) )
@@ -285,13 +263,13 @@ const ticketButtons = () => {
//UNPIN TICKET //UNPIN TICKET
buttons.add(new api.ODButton("opendiscord:unpin-ticket")) buttons.add(new api.ODButton("opendiscord:unpin-ticket"))
buttons.get("opendiscord:unpin-ticket").workers.add( buttons.get("opendiscord:unpin-ticket").workers.add(
new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,source) => { new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params const {guild,channel,ticket} = params
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:unpin-ticket_"+source) instance.setCustomId("od:unpin-ticket")
instance.setColor("gray") instance.setColor("gray")
instance.setEmoji(generalConfig.data.system.pinEmoji) instance.setEmoji(generalConfig.data.ticketSystem.pinEmoji)
instance.setLabel(lang.getTranslation("actions.buttons.unpin")) instance.setLabel(lang.getTranslation("actions.buttons.unpin"))
}) })
) )
@@ -301,7 +279,7 @@ const transcriptButtons = () => {
//TRANSCRIPT HTML VISIT //TRANSCRIPT HTML VISIT
buttons.add(new api.ODButton("opendiscord:transcript-html-visit")) buttons.add(new api.ODButton("opendiscord:transcript-html-visit"))
buttons.get("opendiscord:transcript-html-visit").workers.add( buttons.get("opendiscord:transcript-html-visit").workers.add(
new api.ODWorker("opendiscord:transcript-html-visit",0,async (instance,params,source) => { new api.ODWorker("opendiscord:transcript-html-visit",0,async (instance,params,origin) => {
const {result} = params const {result} = params
instance.setMode("url") instance.setMode("url")
if (result.data) instance.setUrl(result.data.url) if (result.data) instance.setUrl(result.data.url)
@@ -314,9 +292,9 @@ const transcriptButtons = () => {
//TRANSCRIPT ERROR RETRY //TRANSCRIPT ERROR RETRY
buttons.add(new api.ODButton("opendiscord:transcript-error-retry")) buttons.add(new api.ODButton("opendiscord:transcript-error-retry"))
buttons.get("opendiscord:transcript-error-retry").workers.add( buttons.get("opendiscord:transcript-error-retry").workers.add(
new api.ODWorker("opendiscord:transcript-error-retry",0,async (instance,params,source) => { new api.ODWorker("opendiscord:transcript-error-retry",0,async (instance,params,origin) => {
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:transcript-error-retry_"+source) instance.setCustomId("od:transcript-error-retry_"+origin)
instance.setColor("gray") instance.setColor("gray")
instance.setEmoji("🔄") instance.setEmoji("🔄")
instance.setLabel(lang.getTranslation("transcripts.errors.retry")) instance.setLabel(lang.getTranslation("transcripts.errors.retry"))
@@ -326,9 +304,9 @@ const transcriptButtons = () => {
//TRANSCRIPT ERROR CONTINUE //TRANSCRIPT ERROR CONTINUE
buttons.add(new api.ODButton("opendiscord:transcript-error-continue")) buttons.add(new api.ODButton("opendiscord:transcript-error-continue"))
buttons.get("opendiscord:transcript-error-continue").workers.add( buttons.get("opendiscord:transcript-error-continue").workers.add(
new api.ODWorker("opendiscord:transcript-error-continue",0,async (instance,params,source) => { new api.ODWorker("opendiscord:transcript-error-continue",0,async (instance,params,origin) => {
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:transcript-error-continue_"+source) instance.setCustomId("od:transcript-error-continue_"+origin)
instance.setColor("red") instance.setColor("red")
instance.setEmoji("✖") instance.setEmoji("✖")
instance.setLabel(lang.getTranslation("transcripts.errors.continue")) instance.setLabel(lang.getTranslation("transcripts.errors.continue"))
@@ -340,12 +318,13 @@ const clearButtons = () => {
//CLEAR CONTINUE //CLEAR CONTINUE
buttons.add(new api.ODButton("opendiscord:clear-continue")) buttons.add(new api.ODButton("opendiscord:clear-continue"))
buttons.get("opendiscord:clear-continue").workers.add( buttons.get("opendiscord:clear-continue").workers.add(
new api.ODWorker("opendiscord:clear-continue",0,async (instance,params,source) => { new api.ODWorker("opendiscord:clear-continue",0,async (instance,params,origin) => {
instance.setMode("button") instance.setMode("button")
instance.setCustomId("od:clear-continue_"+source+"_"+params.filter) instance.setCustomId("od:clear-continue")
instance.setColor("red") instance.setColor("red")
instance.setEmoji("✖") instance.setEmoji("✖")
instance.setLabel(lang.getTranslation("actions.buttons.clear")) instance.setLabel(lang.getTranslation("actions.buttons.clear"))
instance.setDisabled(params.inProgress)
}) })
) )
} }
+2 -2
View File
@@ -1,12 +1,12 @@
/////////////////////////////////////// ///////////////////////////////////////
//DROPDOWN BUILDERS //DROPDOWN BUILDERS
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const dropdowns = opendiscord.builders.dropdowns const dropdowns = opendiscord.builders.dropdowns
export const registerAllDropdowns = async () => { export async function registerAllDropdowns(){
panelDropdowns() panelDropdowns()
} }
+169 -145
View File
@@ -1,7 +1,7 @@
/////////////////////////////////////// ///////////////////////////////////////
//EMBED BUILDERS //EMBED BUILDERS
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
import nodepath from "path" import nodepath from "path"
@@ -9,7 +9,7 @@ const embeds = opendiscord.builders.embeds
const lang = opendiscord.languages const lang = opendiscord.languages
const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfig = opendiscord.configs.get("opendiscord:general")
export const registerAllEmbeds = async () => { export async function registerAllEmbeds(){
errorEmbeds() errorEmbeds()
helpMenuEmbeds() helpMenuEmbeds()
statsEmbeds() statsEmbeds()
@@ -23,12 +23,12 @@ export const registerAllEmbeds = async () => {
extraEmbeds() extraEmbeds()
} }
/**Utility function to get the translated "method" from the source. Mostly used in error embeds. */ /**Utility function to get the translated "method" from the origin. Mostly used in error embeds. */
const getMethodFromSource = (source:"slash"|"text"|"button"|"dropdown"|"modal"|"other"): string => { const getMethodFromOrigin = (origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other"): string => {
if (source == "slash" || source == "text") return lang.getTranslation("params.lowercase.command") if (origin == "slash" || origin == "text") return lang.getTranslation("params.lowercase.command")
else if (source == "button") return lang.getTranslation("params.lowercase.button") else if (origin == "button") return lang.getTranslation("params.lowercase.button")
else if (source == "dropdown") return lang.getTranslation("params.lowercase.dropdown") else if (origin == "dropdown") return lang.getTranslation("params.lowercase.dropdown")
else if (source == "modal") return lang.getTranslation("params.lowercase.modal") else if (origin == "modal") return lang.getTranslation("params.lowercase.modal")
else return lang.getTranslation("params.lowercase.method") else return lang.getTranslation("params.lowercase.method")
} }
//lang.getTranslation() //lang.getTranslation()
@@ -37,12 +37,12 @@ const errorEmbeds = () => {
//ERROR //ERROR
embeds.add(new api.ODEmbed("opendiscord:error")) embeds.add(new api.ODEmbed("opendiscord:error"))
embeds.get("opendiscord:error").workers.add( embeds.get("opendiscord:error").workers.add(
new api.ODWorker("opendiscord:error",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error",0,async (instance,params,origin) => {
const {user,error,layout,customTitle} = params const {user,error,layout,customTitle} = params
const method = getMethodFromSource(source) const method = getMethodFromOrigin(origin)
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",customTitle ?? lang.getTranslation("errors.titles.internalError"))) instance.setTitle(utilities.emojiTitle("❌",customTitle ?? lang.getTranslation("errors.titles.internalError")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.internalError",[method]) + (layout == "simple") ? "\n"+error : "") instance.setDescription(lang.getTranslationWithParams("errors.descriptions.internalError",[method]) + (layout == "simple") ? "\n"+error : "")
@@ -75,7 +75,7 @@ const errorEmbeds = () => {
}) })
const commandSyntax = "**"+error.prefix+error.name+" "+optionSyntax.join(" ")+"**" const commandSyntax = "**"+error.prefix+error.name+" "+optionSyntax.join(" ")+"**"
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.optionMissing"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.optionMissing")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.optionMissing")) instance.setDescription(lang.getTranslation("errors.descriptions.optionMissing"))
@@ -130,7 +130,7 @@ const errorEmbeds = () => {
else if (error.reason == "channel_type" && error.option.type == "channel") reasonValue = lang.getTranslation("errors.optionInvalidReasons.channelType") else if (error.reason == "channel_type" && error.option.type == "channel") reasonValue = lang.getTranslation("errors.optionInvalidReasons.channelType")
else if (error.reason == "not_in_guild") reasonValue = lang.getTranslation("errors.optionInvalidReasons.notInGuild") else if (error.reason == "not_in_guild") reasonValue = lang.getTranslation("errors.optionInvalidReasons.notInGuild")
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.optionInvalid"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.optionInvalid")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.optionInvalid")+"\n"+reasonTitle+": `"+reasonValue+"`") instance.setDescription(lang.getTranslation("errors.descriptions.optionInvalid")+"\n"+reasonTitle+": `"+reasonValue+"`")
@@ -144,7 +144,7 @@ const errorEmbeds = () => {
new api.ODWorker("opendiscord:error-unknown-command",0,async (instance,params) => { new api.ODWorker("opendiscord:error-unknown-command",0,async (instance,params) => {
const {user} = params const {user} = params
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownCommand"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownCommand")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.unknownCommand")) instance.setDescription(lang.getTranslation("errors.descriptions.unknownCommand"))
@@ -154,10 +154,10 @@ const errorEmbeds = () => {
//ERROR NO PERMISSIONS //ERROR NO PERMISSIONS
embeds.add(new api.ODEmbed("opendiscord:error-no-permissions")) embeds.add(new api.ODEmbed("opendiscord:error-no-permissions"))
embeds.get("opendiscord:error-no-permissions").workers.add( embeds.get("opendiscord:error-no-permissions").workers.add(
new api.ODWorker("opendiscord:error-no-permissions",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-no-permissions",0,async (instance,params,origin) => {
const {user,permissions} = params const {user,permissions} = params
const method = getMethodFromSource(source) const method = getMethodFromOrigin(origin)
const renderedPerms = permissions.map((perm) => { const renderedPerms = permissions.map((perm) => {
if (perm == "developer") return "- "+lang.getTranslation("errors.permissions.developer") if (perm == "developer") return "- "+lang.getTranslation("errors.permissions.developer")
@@ -169,7 +169,7 @@ const errorEmbeds = () => {
else if (perm == "discord-administrator") return "- "+lang.getTranslation("errors.permissions.discord-administrator") else if (perm == "discord-administrator") return "- "+lang.getTranslation("errors.permissions.discord-administrator")
}).join("\n") }).join("\n")
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissions",[method])) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissions",[method]))
@@ -180,12 +180,12 @@ const errorEmbeds = () => {
//ERROR NO PERMISSIONS COOLDOWN //ERROR NO PERMISSIONS COOLDOWN
embeds.add(new api.ODEmbed("opendiscord:error-no-permissions-cooldown")) embeds.add(new api.ODEmbed("opendiscord:error-no-permissions-cooldown"))
embeds.get("opendiscord:error-no-permissions-cooldown").workers.add( embeds.get("opendiscord:error-no-permissions-cooldown").workers.add(
new api.ODWorker("opendiscord:error-no-permissions-cooldown",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-no-permissions-cooldown",0,async (instance,params,origin) => {
const {user} = params const {user} = params
const method = getMethodFromSource(source) const method = getMethodFromOrigin(origin)
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissionsCooldown",[method])) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissionsCooldown",[method]))
@@ -196,12 +196,12 @@ const errorEmbeds = () => {
//ERROR NO PERMISSIONS BLACKLISTED //ERROR NO PERMISSIONS BLACKLISTED
embeds.add(new api.ODEmbed("opendiscord:error-no-permissions-blacklisted")) embeds.add(new api.ODEmbed("opendiscord:error-no-permissions-blacklisted"))
embeds.get("opendiscord:error-no-permissions-blacklisted").workers.add( embeds.get("opendiscord:error-no-permissions-blacklisted").workers.add(
new api.ODWorker("opendiscord:error-no-permissions-blacklisted",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-no-permissions-blacklisted",0,async (instance,params,origin) => {
const {user} = params const {user} = params
const method = getMethodFromSource(source) const method = getMethodFromOrigin(origin)
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissionsBlacklist",[method])) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissionsBlacklist",[method]))
@@ -211,10 +211,10 @@ const errorEmbeds = () => {
//ERROR NO PERMISSIONS LIMITS //ERROR NO PERMISSIONS LIMITS
embeds.add(new api.ODEmbed("opendiscord:error-no-permissions-limits")) embeds.add(new api.ODEmbed("opendiscord:error-no-permissions-limits"))
embeds.get("opendiscord:error-no-permissions-limits").workers.add( embeds.get("opendiscord:error-no-permissions-limits").workers.add(
new api.ODWorker("opendiscord:error-no-permissions-limits",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-no-permissions-limits",0,async (instance,params,origin) => {
const {user,limit} = params const {user,limit} = params
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
if (limit == "global") instance.setDescription(lang.getTranslation("errors.descriptions.noPermissionsLimitGlobal")) if (limit == "global") instance.setDescription(lang.getTranslation("errors.descriptions.noPermissionsLimitGlobal"))
@@ -227,12 +227,12 @@ const errorEmbeds = () => {
//ERROR RESPONDER TIMEOUT //ERROR RESPONDER TIMEOUT
embeds.add(new api.ODEmbed("opendiscord:error-responder-timeout")) embeds.add(new api.ODEmbed("opendiscord:error-responder-timeout"))
embeds.get("opendiscord:error-responder-timeout").workers.add( embeds.get("opendiscord:error-responder-timeout").workers.add(
new api.ODWorker("opendiscord:error-responder-timeout",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-responder-timeout",0,async (instance,params,origin) => {
const {user} = params const {user} = params
const method = getMethodFromSource(source) const method = getMethodFromOrigin(origin)
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.internalError"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.internalError")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.internalError",[method])) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.internalError",[method]))
@@ -244,10 +244,10 @@ const errorEmbeds = () => {
//ERROR TICKET UNKNOWN //ERROR TICKET UNKNOWN
embeds.add(new api.ODEmbed("opendiscord:error-ticket-unknown")) embeds.add(new api.ODEmbed("opendiscord:error-ticket-unknown"))
embeds.get("opendiscord:error-ticket-unknown").workers.add( embeds.get("opendiscord:error-ticket-unknown").workers.add(
new api.ODWorker("opendiscord:error-ticket-unknown",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-ticket-unknown",0,async (instance,params,origin) => {
const {user} = params const {user} = params
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownTicket"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownTicket")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.unknownTicket")) instance.setDescription(lang.getTranslation("errors.descriptions.unknownTicket"))
@@ -258,10 +258,10 @@ const errorEmbeds = () => {
//ERROR TICKET DEPRECATED //ERROR TICKET DEPRECATED
embeds.add(new api.ODEmbed("opendiscord:error-ticket-deprecated")) embeds.add(new api.ODEmbed("opendiscord:error-ticket-deprecated"))
embeds.get("opendiscord:error-ticket-deprecated").workers.add( embeds.get("opendiscord:error-ticket-deprecated").workers.add(
new api.ODWorker("opendiscord:error-ticket-deprecated",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-ticket-deprecated",0,async (instance,params,origin) => {
const {user} = params const {user} = params
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.deprecatedTicket"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.deprecatedTicket")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.deprecatedTicket")) instance.setDescription(lang.getTranslation("errors.descriptions.deprecatedTicket"))
@@ -272,7 +272,7 @@ const errorEmbeds = () => {
//ERROR OPTION UNKNOWN //ERROR OPTION UNKNOWN
embeds.add(new api.ODEmbed("opendiscord:error-option-unknown")) embeds.add(new api.ODEmbed("opendiscord:error-option-unknown"))
embeds.get("opendiscord:error-option-unknown").workers.add( embeds.get("opendiscord:error-option-unknown").workers.add(
new api.ODWorker("opendiscord:error-option-unknown",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-option-unknown",0,async (instance,params,origin) => {
const {user} = params const {user} = params
const renderedTicketOptions = opendiscord.options.getAll().map((option) => { const renderedTicketOptions = opendiscord.options.getAll().map((option) => {
@@ -281,7 +281,7 @@ const errorEmbeds = () => {
}else return "- `"+option.id.value+"`" }else return "- `"+option.id.value+"`"
}).join("\n") }).join("\n")
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownOption"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownOption")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setFooter(lang.getTranslation("errors.descriptions.askForInfo")) instance.setFooter(lang.getTranslation("errors.descriptions.askForInfo"))
@@ -292,7 +292,7 @@ const errorEmbeds = () => {
//ERROR PANEL UNKNOWN //ERROR PANEL UNKNOWN
embeds.add(new api.ODEmbed("opendiscord:error-panel-unknown")) embeds.add(new api.ODEmbed("opendiscord:error-panel-unknown"))
embeds.get("opendiscord:error-panel-unknown").workers.add( embeds.get("opendiscord:error-panel-unknown").workers.add(
new api.ODWorker("opendiscord:error-panel-unknown",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-panel-unknown",0,async (instance,params,origin) => {
const {user} = params const {user} = params
const renderedPanels = opendiscord.panels.getAll().map((panel) => { const renderedPanels = opendiscord.panels.getAll().map((panel) => {
@@ -301,7 +301,7 @@ const errorEmbeds = () => {
}else return "- `"+panel.id.value+"`" }else return "- `"+panel.id.value+"`"
}).join("\n") }).join("\n")
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownPanel"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownPanel")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.addFields({name:lang.getTranslation("params.uppercase.validPanels")+":",value:renderedPanels}) instance.addFields({name:lang.getTranslation("params.uppercase.validPanels")+":",value:renderedPanels})
@@ -312,12 +312,12 @@ const errorEmbeds = () => {
//ERROR NOT IN GUILD //ERROR NOT IN GUILD
embeds.add(new api.ODEmbed("opendiscord:error-not-in-guild")) embeds.add(new api.ODEmbed("opendiscord:error-not-in-guild"))
embeds.get("opendiscord:error-not-in-guild").workers.add( embeds.get("opendiscord:error-not-in-guild").workers.add(
new api.ODWorker("opendiscord:error-not-in-guild",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-not-in-guild",0,async (instance,params,origin) => {
const {user} = params const {user} = params
const method = getMethodFromSource(source) const method = getMethodFromOrigin(origin)
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.notInGuild"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.notInGuild")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.notInGuild",[method])) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.notInGuild",[method]))
@@ -327,19 +327,43 @@ const errorEmbeds = () => {
//ERROR CHANNEL RENAME //ERROR CHANNEL RENAME
embeds.add(new api.ODEmbed("opendiscord:error-channel-rename")) embeds.add(new api.ODEmbed("opendiscord:error-channel-rename"))
embeds.get("opendiscord:error-channel-rename").workers.add( embeds.get("opendiscord:error-channel-rename").workers.add(
new api.ODWorker("opendiscord:error-channel-rename",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-channel-rename",0,async (instance,params,origin) => {
const {channel,user,originalName,newName} = params const {channel,user,originalName,newName} = params
const method = (source == "ticket-move" || source == "ticket-pin" || source == "ticket-rename" || source == "ticket-unpin" || source == "ticket-priority" || source == "ticket-transfer") ? source : getMethodFromSource(source) const method = (origin == "ticket-move" || origin == "ticket-pin" || origin == "ticket-rename" || origin == "ticket-unpin" || origin == "ticket-priority" || origin == "ticket-transfer") ? origin : getMethodFromOrigin(origin)
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.channelRename"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.channelRename")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.channelRename")) instance.setDescription(lang.getTranslation("errors.descriptions.channelRename"))
instance.setFooter(lang.getTranslationWithParams("errors.descriptions.channelRenameSource",[method])) instance.setFooter(lang.getTranslationWithParams("errors.descriptions.channelRenameSource",[method]))
instance.addFields( instance.addFields(
{name:lang.getTranslation("params.uppercase.originalName")+":",value:"```#"+originalName+"```",inline:false}, {name:lang.getTranslation("params.uppercase.originalName")+":",value:"```#"+originalName+"```",inline:true},
{name:lang.getTranslation("params.uppercase.newName")+":",value:"```#"+newName+"```",inline:false} {name:lang.getTranslation("params.uppercase.newName")+":",value:"```#"+newName+"```",inline:true}
)
})
)
//ERROR CHANNEL CATEGORY
embeds.add(new api.ODEmbed("opendiscord:error-channel-category"))
embeds.get("opendiscord:error-channel-category").workers.add(
new api.ODWorker("opendiscord:error-channel-category",0,async (instance,params,origin) => {
const {channel,user,originalCategory,newCategory} = params
const method = (origin == "ticket-create" || origin == "ticket-close" || origin == "ticket-reopen" || origin == "ticket-claim" || origin == "ticket-unclaim" || origin == "ticket-move") ? origin : getMethodFromOrigin(origin)
instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
//TODO TRANSLATION!!!
instance.setTitle(utilities.emojiTitle("❌","Unable To Change Category"))
instance.setAuthor(user.displayName,user.displayAvatarURL())
//TODO TRANSLATION!!!
instance.setDescription("Due to Discord rate limits, the channel category could not be changed immediately. It will be changed automatically within 10 minutes if the bot remains online.")
instance.setFooter(lang.getTranslationWithParams("errors.descriptions.channelRenameSource",[method]))
instance.addFields(
//TODO TRANSLATION!!!
{name:"Original Category"+":",value:"```"+originalCategory+"```",inline:true},
//TODO TRANSLATION!!!
{name:"New Category"+":",value:"```"+newCategory+"```",inline:true}
) )
}) })
) )
@@ -347,12 +371,12 @@ const errorEmbeds = () => {
//ERROR TICKET BUSY //ERROR TICKET BUSY
embeds.add(new api.ODEmbed("opendiscord:error-ticket-busy")) embeds.add(new api.ODEmbed("opendiscord:error-ticket-busy"))
embeds.get("opendiscord:error-ticket-busy").workers.add( embeds.get("opendiscord:error-ticket-busy").workers.add(
new api.ODWorker("opendiscord:error-ticket-busy",0,async (instance,params,source) => { new api.ODWorker("opendiscord:error-ticket-busy",0,async (instance,params,origin) => {
const {user} = params const {user} = params
const method = getMethodFromSource(source) const method = getMethodFromOrigin(origin)
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.busy"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.busy")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.busy",[method])) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.busy",[method]))
@@ -387,7 +411,7 @@ const statsEmbeds = () => {
new api.ODWorker("opendiscord:stats-global",0,async (instance,params) => { new api.ODWorker("opendiscord:stats-global",0,async (instance,params) => {
const {guild,channel,user} = params const {guild,channel,user} = params
const scope = opendiscord.stats.get("opendiscord:global") const scope = opendiscord.statistics.get("opendiscord:global")
if (!scope) return if (!scope) return
const data = await scope.render("GLOBAL",guild,channel,user) const data = await scope.render("GLOBAL",guild,channel,user)
@@ -397,7 +421,7 @@ const statsEmbeds = () => {
if (opendiscord.permissions.hasPermissions("owner",await opendiscord.permissions.getPermissions(user,channel,guild))){ if (opendiscord.permissions.hasPermissions("owner",await opendiscord.permissions.getPermissions(user,channel,guild))){
//show system data when owner or developer //show system data when owner or developer
const systemScope = opendiscord.stats.get("opendiscord:system") const systemScope = opendiscord.statistics.get("opendiscord:system")
if (!systemScope) return if (!systemScope) return
const systemData = await systemScope.render("GLOBAL",guild,channel,user) const systemData = await systemScope.render("GLOBAL",guild,channel,user)
instance.addFields({name:systemScope.name,value:systemData,inline:false}) instance.addFields({name:systemScope.name,value:systemData,inline:false})
@@ -411,9 +435,9 @@ const statsEmbeds = () => {
new api.ODWorker("opendiscord:stats-ticket",0,async (instance,params) => { new api.ODWorker("opendiscord:stats-ticket",0,async (instance,params) => {
const {guild,channel,user,scopeData} = params const {guild,channel,user,scopeData} = params
const scope = opendiscord.stats.get("opendiscord:ticket") const scope = opendiscord.statistics.get("opendiscord:ticket")
const participantsScope = opendiscord.stats.get("opendiscord:participants") const participantsScope = opendiscord.statistics.get("opendiscord:participants")
const messagesScope = opendiscord.stats.get("opendiscord:messages") const messagesScope = opendiscord.statistics.get("opendiscord:messages")
if (!scope || !participantsScope || !messagesScope) return if (!scope || !participantsScope || !messagesScope) return
const data = await scope.render(scopeData.id.value,guild,channel,user) const data = await scope.render(scopeData.id.value,guild,channel,user)
const participantsData = await participantsScope.render(scopeData.id.value,guild,channel,user) const participantsData = await participantsScope.render(scopeData.id.value,guild,channel,user)
@@ -433,7 +457,7 @@ const statsEmbeds = () => {
new api.ODWorker("opendiscord:stats-user",0,async (instance,params) => { new api.ODWorker("opendiscord:stats-user",0,async (instance,params) => {
const {guild,channel,user,scopeData} = params const {guild,channel,user,scopeData} = params
const scope = opendiscord.stats.get("opendiscord:user") const scope = opendiscord.statistics.get("opendiscord:user")
if (!scope) return if (!scope) return
const data = await scope.render(scopeData.id,guild,channel,user) const data = await scope.render(scopeData.id,guild,channel,user)
@@ -477,7 +501,7 @@ const statsEmbeds = () => {
new api.ODWorker("opendiscord:stats-ticket-unknown",0,async (instance,params) => { new api.ODWorker("opendiscord:stats-ticket-unknown",0,async (instance,params) => {
const {user,id} = params const {user,id} = params
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownTicket"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownTicket")))
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.statsError",[discord.channelMention(id)])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.statsError",[discord.channelMention(id)]))
@@ -510,8 +534,8 @@ const panelEmbeds = () => {
instance.setDescription(embedOptions.description) instance.setDescription(embedOptions.description)
} }
if (panel.get("opendiscord:enable-max-tickets-warning-embed").value && generalConfig.data.system.limits.enabled){ if (panel.get("opendiscord:enable-max-tickets-warning-embed").value && generalConfig.data.ticketSystem.limits.enabled){
instance.setDescription(instance.data.description+"\n\n*"+lang.getTranslationWithParams("actions.descriptions.ticketMessageLimit",[generalConfig.data.system.limits.userMaximum.toString()])+"*") instance.setDescription(instance.data.description+"\n\n*"+lang.getTranslationWithParams("actions.descriptions.ticketMessageLimit",[generalConfig.data.ticketSystem.limits.userMaximum.toString()])+"*")
} }
if (panel.get("opendiscord:describe-options-in-embed-fields").value){ if (panel.get("opendiscord:describe-options-in-embed-fields").value){
@@ -529,7 +553,7 @@ const ticketEmbeds = () => {
//TICKET CREATED //TICKET CREATED
embeds.add(new api.ODEmbed("opendiscord:ticket-created")) embeds.add(new api.ODEmbed("opendiscord:ticket-created"))
embeds.get("opendiscord:ticket-created").workers.add( embeds.get("opendiscord:ticket-created").workers.add(
new api.ODWorker("opendiscord:ticket-created",0,async (instance,params,source) => { new api.ODWorker("opendiscord:ticket-created",0,async (instance,params,origin) => {
const {user} = params const {user} = params
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -543,7 +567,7 @@ const ticketEmbeds = () => {
//TICKET CREATED DM //TICKET CREATED DM
embeds.add(new api.ODEmbed("opendiscord:ticket-created-dm")) embeds.add(new api.ODEmbed("opendiscord:ticket-created-dm"))
embeds.get("opendiscord:ticket-created-dm").workers.add( embeds.get("opendiscord:ticket-created-dm").workers.add(
new api.ODWorker("opendiscord:ticket-created-dm",0,async (instance,params,source) => { new api.ODWorker("opendiscord:ticket-created-dm",0,async (instance,params,origin) => {
const {user,ticket} = params const {user,ticket} = params
const embedOptions = ticket.option.get("opendiscord:dm-message-embed").value const embedOptions = ticket.option.get("opendiscord:dm-message-embed").value
@@ -563,10 +587,10 @@ const ticketEmbeds = () => {
//TICKET CREATED LOGS //TICKET CREATED LOGS
embeds.add(new api.ODEmbed("opendiscord:ticket-created-logs")) embeds.add(new api.ODEmbed("opendiscord:ticket-created-logs"))
embeds.get("opendiscord:ticket-created-logs").workers.add( embeds.get("opendiscord:ticket-created-logs").workers.add(
new api.ODWorker("opendiscord:ticket-created-logs",0,async (instance,params,source) => { new api.ODWorker("opendiscord:ticket-created-logs",0,async (instance,params,origin) => {
const {user,ticket} = params const {user,ticket} = params
const method = (source == "panel-button" || source == "panel-dropdown") ? lang.getTranslation("params.uppercase.panel") : (source == "slash" || source == "text") ? lang.getTranslation("params.uppercase.command") : lang.getTranslation("params.uppercase.system") const method = (origin == "panel-button" || origin == "panel-dropdown") ? lang.getTranslation("params.uppercase.panel") : (origin == "slash" || origin == "text") ? lang.getTranslation("params.uppercase.command") : lang.getTranslation("params.uppercase.system")
const blacklisted = opendiscord.blacklist.exists(user.id) ? lang.getTranslation("params.uppercase.true") : lang.getTranslation("params.uppercase.false") const blacklisted = opendiscord.blacklist.exists(user.id) ? lang.getTranslation("params.uppercase.true") : lang.getTranslation("params.uppercase.false")
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -586,7 +610,7 @@ const ticketEmbeds = () => {
//TICKET MESSAGE //TICKET MESSAGE
embeds.add(new api.ODEmbed("opendiscord:ticket-message")) embeds.add(new api.ODEmbed("opendiscord:ticket-message"))
embeds.get("opendiscord:ticket-message").workers.add( embeds.get("opendiscord:ticket-message").workers.add(
new api.ODWorker("opendiscord:ticket-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:ticket-message",0,async (instance,params,origin) => {
const {user,ticket} = params const {user,ticket} = params
const embedOptions = ticket.option.get("opendiscord:ticket-message-embed").value const embedOptions = ticket.option.get("opendiscord:ticket-message-embed").value
@@ -599,12 +623,12 @@ const ticketEmbeds = () => {
if (ticket.option.get("opendiscord:questions").value.length > 0){ if (ticket.option.get("opendiscord:questions").value.length > 0){
//show config fields if mixing is allowed //show config fields if mixing is allowed
if (generalConfig.data.system.displayFieldsWithQuestions) instance.addFields(...embedOptions.fields) if (generalConfig.data.ticketSystem.displayFieldsWithQuestions) instance.addFields(...embedOptions.fields)
const answers = ticket.get("opendiscord:answers").value const answers = ticket.get("opendiscord:answers").value
answers.forEach((answer) => { answers.forEach((answer) => {
if (!answer.value || answer.value.length == 0) return if (!answer.value || answer.value.length == 0) return
if (generalConfig.data.system.questionFieldsInCodeBlock) instance.addFields({name:answer.name,value:"```"+answer.value+"```",inline:false}) if (generalConfig.data.ticketSystem.questionFieldsInCodeBlock) instance.addFields({name:answer.name,value:"```"+answer.value.slice(0,1024-6)+"```",inline:false})
else instance.addFields({name:answer.name,value:answer.value,inline:false}) else instance.addFields({name:answer.name,value:answer.value,inline:false})
}) })
}else if (embedOptions.fields){ }else if (embedOptions.fields){
@@ -625,161 +649,161 @@ const ticketEmbeds = () => {
//TICKET CLOSED //TICKET CLOSED
embeds.add(new api.ODEmbed("opendiscord:close-message")) embeds.add(new api.ODEmbed("opendiscord:close-message"))
embeds.get("opendiscord:close-message").workers.add( embeds.get("opendiscord:close-message").workers.add(
new api.ODWorker("opendiscord:close-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:close-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔒",lang.getTranslation("actions.titles.close"))) instance.setTitle(utilities.emojiTitle("🔒",lang.getTranslation("actions.titles.close")))
instance.setDescription(lang.getTranslation("actions.descriptions.close")) instance.setDescription(lang.getTranslation("actions.descriptions.close"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET REOPENED //TICKET REOPENED
embeds.add(new api.ODEmbed("opendiscord:reopen-message")) embeds.add(new api.ODEmbed("opendiscord:reopen-message"))
embeds.get("opendiscord:reopen-message").workers.add( embeds.get("opendiscord:reopen-message").workers.add(
new api.ODWorker("opendiscord:reopen-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:reopen-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔓",lang.getTranslation("actions.titles.reopen"))) instance.setTitle(utilities.emojiTitle("🔓",lang.getTranslation("actions.titles.reopen")))
instance.setDescription(lang.getTranslation("actions.descriptions.reopen")) instance.setDescription(lang.getTranslation("actions.descriptions.reopen"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET DELETED //TICKET DELETED
embeds.add(new api.ODEmbed("opendiscord:delete-message")) embeds.add(new api.ODEmbed("opendiscord:delete-message"))
embeds.get("opendiscord:delete-message").workers.add( embeds.get("opendiscord:delete-message").workers.add(
new api.ODWorker("opendiscord:delete-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:delete-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🗑️",lang.getTranslation("actions.titles.delete"))) instance.setTitle(utilities.emojiTitle("🗑️",lang.getTranslation("actions.titles.delete")))
instance.setDescription(lang.getTranslation("actions.descriptions.delete")) instance.setDescription(lang.getTranslation("actions.descriptions.delete"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET CLAIMED //TICKET CLAIMED
embeds.add(new api.ODEmbed("opendiscord:claim-message")) embeds.add(new api.ODEmbed("opendiscord:claim-message"))
embeds.get("opendiscord:claim-message").workers.add( embeds.get("opendiscord:claim-message").workers.add(
new api.ODWorker("opendiscord:claim-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:claim-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("👋",lang.getTranslation("actions.titles.claim"))) instance.setTitle(utilities.emojiTitle("👋",lang.getTranslation("actions.titles.claim")))
instance.setDescription(lang.getTranslation("actions.descriptions.claim")) instance.setDescription(lang.getTranslation("actions.descriptions.claim"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET UNCLAIMED //TICKET UNCLAIMED
embeds.add(new api.ODEmbed("opendiscord:unclaim-message")) embeds.add(new api.ODEmbed("opendiscord:unclaim-message"))
embeds.get("opendiscord:unclaim-message").workers.add( embeds.get("opendiscord:unclaim-message").workers.add(
new api.ODWorker("opendiscord:unclaim-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:unclaim-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("↩️",lang.getTranslation("actions.titles.unclaim"))) instance.setTitle(utilities.emojiTitle("↩️",lang.getTranslation("actions.titles.unclaim")))
instance.setDescription(lang.getTranslation("actions.descriptions.unclaim")) instance.setDescription(lang.getTranslation("actions.descriptions.unclaim"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET PINNED //TICKET PINNED
embeds.add(new api.ODEmbed("opendiscord:pin-message")) embeds.add(new api.ODEmbed("opendiscord:pin-message"))
embeds.get("opendiscord:pin-message").workers.add( embeds.get("opendiscord:pin-message").workers.add(
new api.ODWorker("opendiscord:pin-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:pin-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.pin"))) instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.pin")))
instance.setDescription(lang.getTranslation("actions.descriptions.pin")) instance.setDescription(lang.getTranslation("actions.descriptions.pin"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET UNPINNED //TICKET UNPINNED
embeds.add(new api.ODEmbed("opendiscord:unpin-message")) embeds.add(new api.ODEmbed("opendiscord:unpin-message"))
embeds.get("opendiscord:unpin-message").workers.add( embeds.get("opendiscord:unpin-message").workers.add(
new api.ODWorker("opendiscord:unpin-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:unpin-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.unpin"))) instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.unpin")))
instance.setDescription(lang.getTranslation("actions.descriptions.unpin")) instance.setDescription(lang.getTranslation("actions.descriptions.unpin"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET RENAMED //TICKET RENAMED
embeds.add(new api.ODEmbed("opendiscord:rename-message")) embeds.add(new api.ODEmbed("opendiscord:rename-message"))
embeds.get("opendiscord:rename-message").workers.add( embeds.get("opendiscord:rename-message").workers.add(
new api.ODWorker("opendiscord:rename-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:rename-message",0,async (instance,params,origin) => {
const {user,ticket,reason,data} = params const {user,ticket,reason,data} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔄",lang.getTranslation("actions.titles.rename"))) instance.setTitle(utilities.emojiTitle("🔄",lang.getTranslation("actions.titles.rename")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.rename",["`#"+data+"`"])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.rename",["`#"+data+"`"]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET MOVED //TICKET MOVED
embeds.add(new api.ODEmbed("opendiscord:move-message")) embeds.add(new api.ODEmbed("opendiscord:move-message"))
embeds.get("opendiscord:move-message").workers.add( embeds.get("opendiscord:move-message").workers.add(
new api.ODWorker("opendiscord:move-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:move-message",0,async (instance,params,origin) => {
const {user,ticket,reason,data} = params const {user,ticket,reason,data} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔀",lang.getTranslation("actions.titles.move"))) instance.setTitle(utilities.emojiTitle("🔀",lang.getTranslation("actions.titles.move")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.move",["`"+data.get("opendiscord:name").value+"`"])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.move",["`"+data.get("opendiscord:name").value+"`"]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET USER ADDED //TICKET USER ADDED
embeds.add(new api.ODEmbed("opendiscord:add-message")) embeds.add(new api.ODEmbed("opendiscord:add-message"))
embeds.get("opendiscord:add-message").workers.add( embeds.get("opendiscord:add-message").workers.add(
new api.ODWorker("opendiscord:add-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:add-message",0,async (instance,params,origin) => {
const {user,ticket,reason,data} = params const {user,ticket,reason,data} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("👤",lang.getTranslation("actions.titles.add"))) instance.setTitle(utilities.emojiTitle("👤",lang.getTranslation("actions.titles.add")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.add",[discord.userMention(data.id)])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.add",[discord.userMention(data.id)]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET USER REMOVED //TICKET USER REMOVED
embeds.add(new api.ODEmbed("opendiscord:remove-message")) embeds.add(new api.ODEmbed("opendiscord:remove-message"))
embeds.get("opendiscord:remove-message").workers.add( embeds.get("opendiscord:remove-message").workers.add(
new api.ODWorker("opendiscord:remove-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:remove-message",0,async (instance,params,origin) => {
const {user,ticket,reason,data} = params const {user,ticket,reason,data} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("👤",lang.getTranslation("actions.titles.remove"))) instance.setTitle(utilities.emojiTitle("👤",lang.getTranslation("actions.titles.remove")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.remove",[discord.userMention(data.id)])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.remove",[discord.userMention(data.id)]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//TICKET ACTION DM //TICKET ACTION DM
embeds.add(new api.ODEmbed("opendiscord:ticket-action-dm")) embeds.add(new api.ODEmbed("opendiscord:ticket-action-dm"))
embeds.get("opendiscord:ticket-action-dm").workers.add( embeds.get("opendiscord:ticket-action-dm").workers.add(
new api.ODWorker("opendiscord:ticket-action-dm",0,async (instance,params,source) => { new api.ODWorker("opendiscord:ticket-action-dm",0,async (instance,params,origin) => {
const {user,mode,ticket,reason,additionalData} = params const {user,mode,ticket,reason,additionalData} = params
const channel = await opendiscord.tickets.getTicketChannel(ticket) const channel = await opendiscord.tickets.getTicketChannel(ticket)
@@ -804,10 +828,10 @@ const ticketEmbeds = () => {
instance.setTitle(utilities.emojiTitle("↩️",lang.getTranslation("actions.titles.unclaim"))) instance.setTitle(utilities.emojiTitle("↩️",lang.getTranslation("actions.titles.unclaim")))
instance.setDescription(lang.getTranslation("actions.logs.unclaimDm")) instance.setDescription(lang.getTranslation("actions.logs.unclaimDm"))
}else if (mode == "pin"){ }else if (mode == "pin"){
instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.pin"))) instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.pin")))
instance.setDescription(lang.getTranslation("actions.logs.pinDm")) instance.setDescription(lang.getTranslation("actions.logs.pinDm"))
}else if (mode == "unpin"){ }else if (mode == "unpin"){
instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.unpin"))) instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.unpin")))
instance.setDescription(lang.getTranslation("actions.logs.unpinDm")) instance.setDescription(lang.getTranslation("actions.logs.unpinDm"))
}else if (mode == "rename"){ }else if (mode == "rename"){
instance.setTitle(utilities.emojiTitle("🔄",lang.getTranslation("actions.titles.rename"))) instance.setTitle(utilities.emojiTitle("🔄",lang.getTranslation("actions.titles.rename")))
@@ -828,7 +852,7 @@ const ticketEmbeds = () => {
//TICKET ACTION LOGS //TICKET ACTION LOGS
embeds.add(new api.ODEmbed("opendiscord:ticket-action-logs")) embeds.add(new api.ODEmbed("opendiscord:ticket-action-logs"))
embeds.get("opendiscord:ticket-action-logs").workers.add( embeds.get("opendiscord:ticket-action-logs").workers.add(
new api.ODWorker("opendiscord:ticket-action-logs",0,async (instance,params,source) => { new api.ODWorker("opendiscord:ticket-action-logs",0,async (instance,params,origin) => {
const {user,mode,ticket,reason,additionalData} = params const {user,mode,ticket,reason,additionalData} = params
const channel = await opendiscord.tickets.getTicketChannel(ticket) const channel = await opendiscord.tickets.getTicketChannel(ticket)
@@ -840,7 +864,7 @@ const ticketEmbeds = () => {
{name:lang.getTranslation("params.uppercase.ticket")+":",value:"```#"+(channel ? channel.name : "<unknown>")+"```",inline:false}, {name:lang.getTranslation("params.uppercase.ticket")+":",value:"```#"+(channel ? channel.name : "<unknown>")+"```",inline:false},
{name:lang.getTranslation("params.uppercase.option")+":",value:"```"+(ticket.option.get("opendiscord:name").value)+"```",inline:false}, {name:lang.getTranslation("params.uppercase.option")+":",value:"```"+(ticket.option.get("opendiscord:name").value)+"```",inline:false},
) )
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```",inline:false}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```",inline:false})
if (mode == "close"){ if (mode == "close"){
instance.setTitle(utilities.emojiTitle("🔒",lang.getTranslation("actions.titles.close"))) instance.setTitle(utilities.emojiTitle("🔒",lang.getTranslation("actions.titles.close")))
@@ -858,10 +882,10 @@ const ticketEmbeds = () => {
instance.setTitle(utilities.emojiTitle("↩️",lang.getTranslation("actions.titles.unclaim"))) instance.setTitle(utilities.emojiTitle("↩️",lang.getTranslation("actions.titles.unclaim")))
instance.setDescription(lang.getTranslationWithParams("actions.logs.unclaimLog",[discord.userMention(user.id)])) instance.setDescription(lang.getTranslationWithParams("actions.logs.unclaimLog",[discord.userMention(user.id)]))
}else if (mode == "pin"){ }else if (mode == "pin"){
instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.pin"))) instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.pin")))
instance.setDescription(lang.getTranslationWithParams("actions.logs.pinLog",[discord.userMention(user.id)])) instance.setDescription(lang.getTranslationWithParams("actions.logs.pinLog",[discord.userMention(user.id)]))
}else if (mode == "unpin"){ }else if (mode == "unpin"){
instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.unpin"))) instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.unpin")))
instance.setDescription(lang.getTranslationWithParams("actions.logs.unpinLog",[discord.userMention(user.id)])) instance.setDescription(lang.getTranslationWithParams("actions.logs.unpinLog",[discord.userMention(user.id)]))
}else if (mode == "rename"){ }else if (mode == "rename"){
instance.setTitle(utilities.emojiTitle("🔄",lang.getTranslation("actions.titles.rename"))) instance.setTitle(utilities.emojiTitle("🔄",lang.getTranslation("actions.titles.rename")))
@@ -884,7 +908,7 @@ const blacklistEmbeds = () => {
//BLACKLIST VIEW //BLACKLIST VIEW
embeds.add(new api.ODEmbed("opendiscord:blacklist-view")) embeds.add(new api.ODEmbed("opendiscord:blacklist-view"))
embeds.get("opendiscord:blacklist-view").workers.add( embeds.get("opendiscord:blacklist-view").workers.add(
new api.ODWorker("opendiscord:blacklist-view",0,async (instance,params,source) => { new api.ODWorker("opendiscord:blacklist-view",0,async (instance,params,origin) => {
const {user} = params const {user} = params
const renderedUsers: string[] = [] const renderedUsers: string[] = []
@@ -904,7 +928,7 @@ const blacklistEmbeds = () => {
//BLACKLIST GET //BLACKLIST GET
embeds.add(new api.ODEmbed("opendiscord:blacklist-get")) embeds.add(new api.ODEmbed("opendiscord:blacklist-get"))
embeds.get("opendiscord:blacklist-get").workers.add( embeds.get("opendiscord:blacklist-get").workers.add(
new api.ODWorker("opendiscord:blacklist-get",0,async (instance,params,source) => { new api.ODWorker("opendiscord:blacklist-get",0,async (instance,params,origin) => {
const {user,data} = params const {user,data} = params
const blacklist = opendiscord.blacklist.get(data.id) const blacklist = opendiscord.blacklist.get(data.id)
@@ -914,7 +938,7 @@ const blacklistEmbeds = () => {
if (blacklist){ if (blacklist){
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.blacklistGetSuccess",[discord.userMention(data.id)])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.blacklistGetSuccess",[discord.userMention(data.id)]))
if (blacklist.reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(blacklist.reason ?? "/")+"```"}) if (blacklist.reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(blacklist.reason ?? "/")+"```"})
}else instance.setDescription("*"+lang.getTranslationWithParams("actions.descriptions.blacklistGetEmpty",[discord.userMention(data.id)])+"*") }else instance.setDescription("*"+lang.getTranslationWithParams("actions.descriptions.blacklistGetEmpty",[discord.userMention(data.id)])+"*")
}) })
@@ -923,35 +947,35 @@ const blacklistEmbeds = () => {
//BLACKLIST ADD //BLACKLIST ADD
embeds.add(new api.ODEmbed("opendiscord:blacklist-add")) embeds.add(new api.ODEmbed("opendiscord:blacklist-add"))
embeds.get("opendiscord:blacklist-add").workers.add( embeds.get("opendiscord:blacklist-add").workers.add(
new api.ODWorker("opendiscord:blacklist-add",0,async (instance,params,source) => { new api.ODWorker("opendiscord:blacklist-add",0,async (instance,params,origin) => {
const {user,data,reason} = params const {user,data,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🚫",lang.getTranslation("actions.titles.blacklistAdd"))) instance.setTitle(utilities.emojiTitle("🚫",lang.getTranslation("actions.titles.blacklistAdd")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.blacklistAdd",[discord.userMention(data.id)])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.blacklistAdd",[discord.userMention(data.id)]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//BLACKLIST REMOVE //BLACKLIST REMOVE
embeds.add(new api.ODEmbed("opendiscord:blacklist-remove")) embeds.add(new api.ODEmbed("opendiscord:blacklist-remove"))
embeds.get("opendiscord:blacklist-remove").workers.add( embeds.get("opendiscord:blacklist-remove").workers.add(
new api.ODWorker("opendiscord:blacklist-remove",0,async (instance,params,source) => { new api.ODWorker("opendiscord:blacklist-remove",0,async (instance,params,origin) => {
const {user,data,reason} = params const {user,data,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🆓",lang.getTranslation("actions.titles.blacklistRemove"))) instance.setTitle(utilities.emojiTitle("🆓",lang.getTranslation("actions.titles.blacklistRemove")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.blacklistRemove",[discord.userMention(data.id)])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.blacklistRemove",[discord.userMention(data.id)]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//BLACKLIST DM //BLACKLIST DM
embeds.add(new api.ODEmbed("opendiscord:blacklist-dm")) embeds.add(new api.ODEmbed("opendiscord:blacklist-dm"))
embeds.get("opendiscord:blacklist-dm").workers.add( embeds.get("opendiscord:blacklist-dm").workers.add(
new api.ODWorker("opendiscord:blacklist-dm",0,async (instance,params,source) => { new api.ODWorker("opendiscord:blacklist-dm",0,async (instance,params,origin) => {
const {user,mode,data,reason} = params const {user,mode,data,reason} = params
const title = (mode == "add") ? lang.getTranslation("actions.titles.blacklistAddDm") : lang.getTranslation("actions.titles.blacklistRemoveDm") const title = (mode == "add") ? lang.getTranslation("actions.titles.blacklistAddDm") : lang.getTranslation("actions.titles.blacklistRemoveDm")
@@ -961,14 +985,14 @@ const blacklistEmbeds = () => {
instance.setTitle(utilities.emojiTitle((mode == "add") ? "🚫" : "🆓",title)) instance.setTitle(utilities.emojiTitle((mode == "add") ? "🚫" : "🆓",title))
instance.setTimestamp(new Date()) instance.setTimestamp(new Date())
instance.setDescription(text) instance.setDescription(text)
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//BLACKLIST LOGS //BLACKLIST LOGS
embeds.add(new api.ODEmbed("opendiscord:blacklist-logs")) embeds.add(new api.ODEmbed("opendiscord:blacklist-logs"))
embeds.get("opendiscord:blacklist-logs").workers.add( embeds.get("opendiscord:blacklist-logs").workers.add(
new api.ODWorker("opendiscord:blacklist-logs",0,async (instance,params,source) => { new api.ODWorker("opendiscord:blacklist-logs",0,async (instance,params,origin) => {
const {user,mode,data,reason} = params const {user,mode,data,reason} = params
const title = (mode == "add") ? lang.getTranslation("actions.titles.blacklistAdd") : lang.getTranslation("actions.titles.blacklistRemove") const title = (mode == "add") ? lang.getTranslation("actions.titles.blacklistAdd") : lang.getTranslation("actions.titles.blacklistRemove")
@@ -980,7 +1004,7 @@ const blacklistEmbeds = () => {
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setTimestamp(new Date()) instance.setTimestamp(new Date())
instance.setDescription(text) instance.setDescription(text)
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
} }
@@ -989,7 +1013,7 @@ const transcriptEmbeds = () => {
//TRANSCRIPT TEXT READY //TRANSCRIPT TEXT READY
embeds.add(new api.ODEmbed("opendiscord:transcript-text-ready")) embeds.add(new api.ODEmbed("opendiscord:transcript-text-ready"))
embeds.get("opendiscord:transcript-text-ready").workers.add( embeds.get("opendiscord:transcript-text-ready").workers.add(
new api.ODWorker("opendiscord:transcript-text-ready",0,async (instance,params,source) => { new api.ODWorker("opendiscord:transcript-text-ready",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler} = params const {guild,channel,user,ticket,compiler} = params
const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts") const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts")
@@ -1007,11 +1031,11 @@ const transcriptEmbeds = () => {
}catch{} }catch{}
} }
if (source == "channel") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdChannel",[lang.getTranslation("params.lowercase.text")])) if (origin == "channel") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdChannel",[lang.getTranslation("params.lowercase.text")]))
else if (source == "creator-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdCreator",[lang.getTranslation("params.lowercase.text")])) else if (origin == "creator-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdCreator",[lang.getTranslation("params.lowercase.text")]))
else if (source == "participant-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdParticipant",[lang.getTranslation("params.lowercase.text")])) else if (origin == "participant-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdParticipant",[lang.getTranslation("params.lowercase.text")]))
else if (source == "active-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdActiveAdmin",[lang.getTranslation("params.lowercase.text")])) else if (origin == "active-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdActiveAdmin",[lang.getTranslation("params.lowercase.text")]))
else if (source == "every-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdEveryAdmin",[lang.getTranslation("params.lowercase.text")])) else if (origin == "every-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdEveryAdmin",[lang.getTranslation("params.lowercase.text")]))
else instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdOther",[lang.getTranslation("params.lowercase.text")])) else instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdOther",[lang.getTranslation("params.lowercase.text")]))
}) })
) )
@@ -1019,7 +1043,7 @@ const transcriptEmbeds = () => {
//TRANSCRIPT HTML READY //TRANSCRIPT HTML READY
embeds.add(new api.ODEmbed("opendiscord:transcript-html-ready")) embeds.add(new api.ODEmbed("opendiscord:transcript-html-ready"))
embeds.get("opendiscord:transcript-html-ready").workers.add( embeds.get("opendiscord:transcript-html-ready").workers.add(
new api.ODWorker("opendiscord:transcript-html-ready",0,async (instance,params,source) => { new api.ODWorker("opendiscord:transcript-html-ready",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,result} = params const {guild,channel,user,ticket,compiler,result} = params
const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts") const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts")
@@ -1038,11 +1062,11 @@ const transcriptEmbeds = () => {
}catch{} }catch{}
} }
if (source == "channel") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdChannel",[lang.getTranslation("params.lowercase.html")])) if (origin == "channel") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdChannel",[lang.getTranslation("params.lowercase.html")]))
else if (source == "creator-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdCreator",[lang.getTranslation("params.lowercase.html")])) else if (origin == "creator-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdCreator",[lang.getTranslation("params.lowercase.html")]))
else if (source == "participant-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdParticipant",[lang.getTranslation("params.lowercase.html")])) else if (origin == "participant-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdParticipant",[lang.getTranslation("params.lowercase.html")]))
else if (source == "active-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdActiveAdmin",[lang.getTranslation("params.lowercase.html")])) else if (origin == "active-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdActiveAdmin",[lang.getTranslation("params.lowercase.html")]))
else if (source == "every-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdEveryAdmin",[lang.getTranslation("params.lowercase.html")])) else if (origin == "every-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdEveryAdmin",[lang.getTranslation("params.lowercase.html")]))
else instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdOther",[lang.getTranslation("params.lowercase.html")])) else instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdOther",[lang.getTranslation("params.lowercase.html")]))
}) })
) )
@@ -1050,7 +1074,7 @@ const transcriptEmbeds = () => {
//TRANSCRIPT HTML PROGRESS //TRANSCRIPT HTML PROGRESS
embeds.add(new api.ODEmbed("opendiscord:transcript-html-progress")) embeds.add(new api.ODEmbed("opendiscord:transcript-html-progress"))
embeds.get("opendiscord:transcript-html-progress").workers.add( embeds.get("opendiscord:transcript-html-progress").workers.add(
new api.ODWorker("opendiscord:transcript-html-progress",0,async (instance,params,source) => { new api.ODWorker("opendiscord:transcript-html-progress",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,remaining} = params const {guild,channel,user,ticket,compiler,remaining} = params
const remainingDate = new Date(new Date().getTime()+remaining) const remainingDate = new Date(new Date().getTime()+remaining)
@@ -1076,15 +1100,15 @@ const transcriptEmbeds = () => {
//TRANSCRIPT ERROR //TRANSCRIPT ERROR
embeds.add(new api.ODEmbed("opendiscord:transcript-error")) embeds.add(new api.ODEmbed("opendiscord:transcript-error"))
embeds.get("opendiscord:transcript-error").workers.add( embeds.get("opendiscord:transcript-error").workers.add(
new api.ODWorker("opendiscord:transcript-error",0,async (instance,params,source) => { new api.ODWorker("opendiscord:transcript-error",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,reason} = params const {guild,channel,user,ticket,compiler,reason} = params
instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("transcripts.errors.title"))) instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("transcripts.errors.title")))
instance.setTimestamp(new Date()) instance.setTimestamp(new Date())
instance.setDescription(lang.getTranslation("transcripts.errors.error")) instance.setDescription(lang.getTranslation("transcripts.errors.error"))
instance.setFooter(lang.getTranslation("errors.descriptions.askForInfo")) instance.setFooter(lang.getTranslation("errors.descriptions.askForInfo"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
} }
@@ -1093,7 +1117,7 @@ const roleEmbeds = () => {
//REACTION ROLE //REACTION ROLE
embeds.add(new api.ODEmbed("opendiscord:reaction-role")) embeds.add(new api.ODEmbed("opendiscord:reaction-role"))
embeds.get("opendiscord:reaction-role").workers.add( embeds.get("opendiscord:reaction-role").workers.add(
new api.ODWorker("opendiscord:reaction-role",0,async (instance,params,source) => { new api.ODWorker("opendiscord:reaction-role",0,async (instance,params,origin) => {
const {guild,user,role,result} = params const {guild,user,role,result} = params
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -1117,7 +1141,7 @@ const roleEmbeds = () => {
//REACTION ROLE DM //REACTION ROLE DM
embeds.add(new api.ODEmbed("opendiscord:reaction-role-dm")) embeds.add(new api.ODEmbed("opendiscord:reaction-role-dm"))
embeds.get("opendiscord:reaction-role-dm").workers.add( embeds.get("opendiscord:reaction-role-dm").workers.add(
new api.ODWorker("opendiscord:reaction-role-dm",0,async (instance,params,source) => { new api.ODWorker("opendiscord:reaction-role-dm",0,async (instance,params,origin) => {
const {guild,user,role,result} = params const {guild,user,role,result} = params
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -1143,7 +1167,7 @@ const roleEmbeds = () => {
//REACTION ROLE LOGS //REACTION ROLE LOGS
embeds.add(new api.ODEmbed("opendiscord:reaction-role-logs")) embeds.add(new api.ODEmbed("opendiscord:reaction-role-logs"))
embeds.get("opendiscord:reaction-role-logs").workers.add( embeds.get("opendiscord:reaction-role-logs").workers.add(
new api.ODWorker("opendiscord:reaction-role-logs",0,async (instance,params,source) => { new api.ODWorker("opendiscord:reaction-role-logs",0,async (instance,params,origin) => {
const {guild,user,role,result} = params const {guild,user,role,result} = params
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -1171,7 +1195,7 @@ const clearEmbeds = () => {
//CLEAR VERIFY MESSAGE //CLEAR VERIFY MESSAGE
embeds.add(new api.ODEmbed("opendiscord:clear-verify-message")) embeds.add(new api.ODEmbed("opendiscord:clear-verify-message"))
embeds.get("opendiscord:clear-verify-message").workers.add( embeds.get("opendiscord:clear-verify-message").workers.add(
new api.ODWorker("opendiscord:clear-verify-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:clear-verify-message",0,async (instance,params,origin) => {
const {guild,channel,user,filter,list} = params const {guild,channel,user,filter,list} = params
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -1189,7 +1213,7 @@ const clearEmbeds = () => {
//CLEAR MESSAGE //CLEAR MESSAGE
embeds.add(new api.ODEmbed("opendiscord:clear-message")) embeds.add(new api.ODEmbed("opendiscord:clear-message"))
embeds.get("opendiscord:clear-message").workers.add( embeds.get("opendiscord:clear-message").workers.add(
new api.ODWorker("opendiscord:clear-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:clear-message",0,async (instance,params,origin) => {
const {guild,channel,user,filter,list} = params const {guild,channel,user,filter,list} = params
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -1206,7 +1230,7 @@ const clearEmbeds = () => {
//CLEAR LOGS //CLEAR LOGS
embeds.add(new api.ODEmbed("opendiscord:clear-logs")) embeds.add(new api.ODEmbed("opendiscord:clear-logs"))
embeds.get("opendiscord:clear-logs").workers.add( embeds.get("opendiscord:clear-logs").workers.add(
new api.ODWorker("opendiscord:clear-logs",0,async (instance,params,source) => { new api.ODWorker("opendiscord:clear-logs",0,async (instance,params,origin) => {
const {guild,channel,user,filter,list} = params const {guild,channel,user,filter,list} = params
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -1226,10 +1250,10 @@ const autoEmbeds = () => {
//AUTOCLOSE MESSAGE //AUTOCLOSE MESSAGE
embeds.add(new api.ODEmbed("opendiscord:autoclose-message")) embeds.add(new api.ODEmbed("opendiscord:autoclose-message"))
embeds.get("opendiscord:autoclose-message").workers.add( embeds.get("opendiscord:autoclose-message").workers.add(
new api.ODWorker("opendiscord:autoclose-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:autoclose-message",0,async (instance,params,origin) => {
const {user,ticket} = params const {user,ticket} = params
const hours: number = ticket.get("opendiscord:autoclose-hours").value const hours: number = ticket.get("opendiscord:autoclose-hours").value
const description = (source == "leave") ? lang.getTranslation("actions.descriptions.autocloseLeave") : lang.getTranslationWithParams("actions.descriptions.autocloseTimeout",[hours.toString()]) const description = (origin == "leave") ? lang.getTranslation("actions.descriptions.autocloseLeave") : lang.getTranslationWithParams("actions.descriptions.autocloseTimeout",[hours.toString()])
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -1242,10 +1266,10 @@ const autoEmbeds = () => {
//AUTODELETE MESSAGE //AUTODELETE MESSAGE
embeds.add(new api.ODEmbed("opendiscord:autodelete-message")) embeds.add(new api.ODEmbed("opendiscord:autodelete-message"))
embeds.get("opendiscord:autodelete-message").workers.add( embeds.get("opendiscord:autodelete-message").workers.add(
new api.ODWorker("opendiscord:autodelete-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:autodelete-message",0,async (instance,params,origin) => {
const {user,ticket} = params const {user,ticket} = params
const days: number = ticket.get("opendiscord:autodelete-days").value const days: number = ticket.get("opendiscord:autodelete-days").value
const description = (source == "leave") ? lang.getTranslation("actions.descriptions.autodeleteLeave") : lang.getTranslationWithParams("actions.descriptions.autodeleteTimeout",[days.toString()]) const description = (origin == "leave") ? lang.getTranslation("actions.descriptions.autodeleteLeave") : lang.getTranslationWithParams("actions.descriptions.autodeleteTimeout",[days.toString()])
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
@@ -1258,56 +1282,56 @@ const autoEmbeds = () => {
//AUTOCLOSE ENABLE //AUTOCLOSE ENABLE
embeds.add(new api.ODEmbed("opendiscord:autoclose-enable")) embeds.add(new api.ODEmbed("opendiscord:autoclose-enable"))
embeds.get("opendiscord:autoclose-enable").workers.add( embeds.get("opendiscord:autoclose-enable").workers.add(
new api.ODWorker("opendiscord:autoclose-enable",0,async (instance,params,source) => { new api.ODWorker("opendiscord:autoclose-enable",0,async (instance,params,origin) => {
const {user,ticket,reason,time} = params const {user,ticket,reason,time} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autocloseEnabled"))) instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autocloseEnabled")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.autocloseEnabled",[time.toString()])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.autocloseEnabled",[time.toString()]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//AUTODELETE ENABLE //AUTODELETE ENABLE
embeds.add(new api.ODEmbed("opendiscord:autodelete-enable")) embeds.add(new api.ODEmbed("opendiscord:autodelete-enable"))
embeds.get("opendiscord:autodelete-enable").workers.add( embeds.get("opendiscord:autodelete-enable").workers.add(
new api.ODWorker("opendiscord:autodelete-enable",0,async (instance,params,source) => { new api.ODWorker("opendiscord:autodelete-enable",0,async (instance,params,origin) => {
const {user,ticket,reason,time} = params const {user,ticket,reason,time} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autodeleteEnabled"))) instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autodeleteEnabled")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.autodeleteEnabled",[time.toString()])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.autodeleteEnabled",[time.toString()]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//AUTOCLOSE DISABLE //AUTOCLOSE DISABLE
embeds.add(new api.ODEmbed("opendiscord:autoclose-disable")) embeds.add(new api.ODEmbed("opendiscord:autoclose-disable"))
embeds.get("opendiscord:autoclose-disable").workers.add( embeds.get("opendiscord:autoclose-disable").workers.add(
new api.ODWorker("opendiscord:autoclose-disable",0,async (instance,params,source) => { new api.ODWorker("opendiscord:autoclose-disable",0,async (instance,params,origin) => {
const {user,ticket,reason} = params const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autocloseDisabled"))) instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autocloseDisabled")))
instance.setDescription(lang.getTranslation("actions.descriptions.autocloseDisabled")) instance.setDescription(lang.getTranslation("actions.descriptions.autocloseDisabled"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//AUTODELETE DISABLE //AUTODELETE DISABLE
embeds.add(new api.ODEmbed("opendiscord:autodelete-disable")) embeds.add(new api.ODEmbed("opendiscord:autodelete-disable"))
embeds.get("opendiscord:autodelete-disable").workers.add( embeds.get("opendiscord:autodelete-disable").workers.add(
new api.ODWorker("opendiscord:autodelete-disable",0,async (instance,params,source) => { new api.ODWorker("opendiscord:autodelete-disable",0,async (instance,params,origin) => {
const {user,ticket,reason} = params const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autodeleteDisabled"))) instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autodeleteDisabled")))
instance.setDescription(lang.getTranslation("actions.descriptions.autodeleteDisabled")) instance.setDescription(lang.getTranslation("actions.descriptions.autodeleteDisabled"))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
} }
@@ -1316,7 +1340,7 @@ const extraEmbeds = () => {
//TOPIC SET //TOPIC SET
embeds.add(new api.ODEmbed("opendiscord:topic-set")) embeds.add(new api.ODEmbed("opendiscord:topic-set"))
embeds.get("opendiscord:topic-set").workers.add( embeds.get("opendiscord:topic-set").workers.add(
new api.ODWorker("opendiscord:topic-set",0,async (instance,params,source) => { new api.ODWorker("opendiscord:topic-set",0,async (instance,params,origin) => {
const {user,topic} = params const {user,topic} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
@@ -1330,21 +1354,21 @@ const extraEmbeds = () => {
//PRIORITY SET //PRIORITY SET
embeds.add(new api.ODEmbed("opendiscord:priority-set")) embeds.add(new api.ODEmbed("opendiscord:priority-set"))
embeds.get("opendiscord:priority-set").workers.add( embeds.get("opendiscord:priority-set").workers.add(
new api.ODWorker("opendiscord:priority-set",0,async (instance,params,source) => { new api.ODWorker("opendiscord:priority-set",0,async (instance,params,origin) => {
const {user,priority,reason} = params const {user,priority,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🚨",lang.getTranslation("actions.titles.prioritySet"))) instance.setTitle(utilities.emojiTitle("🚨",lang.getTranslation("actions.titles.prioritySet")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.prioritySet",["**"+priority.renderDisplayName()+"**",discord.userMention(user.id)])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.prioritySet",["**"+priority.renderDisplayName()+"**",discord.userMention(user.id)]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
//PRIORITY GET //PRIORITY GET
embeds.add(new api.ODEmbed("opendiscord:priority-get")) embeds.add(new api.ODEmbed("opendiscord:priority-get"))
embeds.get("opendiscord:priority-get").workers.add( embeds.get("opendiscord:priority-get").workers.add(
new api.ODWorker("opendiscord:priority-get",0,async (instance,params,source) => { new api.ODWorker("opendiscord:priority-get",0,async (instance,params,origin) => {
const {user,priority} = params const {user,priority} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
@@ -1357,14 +1381,14 @@ const extraEmbeds = () => {
//TRANSFER MESSAGE //TRANSFER MESSAGE
embeds.add(new api.ODEmbed("opendiscord:transfer-message")) embeds.add(new api.ODEmbed("opendiscord:transfer-message"))
embeds.get("opendiscord:transfer-message").workers.add( embeds.get("opendiscord:transfer-message").workers.add(
new api.ODWorker("opendiscord:transfer-message",0,async (instance,params,source) => { new api.ODWorker("opendiscord:transfer-message",0,async (instance,params,origin) => {
const {user,oldCreator,newCreator,reason} = params const {user,oldCreator,newCreator,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor) instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔀",lang.getTranslation("actions.titles.transfer"))) instance.setTitle(utilities.emojiTitle("🔀",lang.getTranslation("actions.titles.transfer")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.transfer",[discord.userMention(oldCreator.id),discord.userMention(newCreator.id),discord.userMention(user.id)])) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.transfer",[discord.userMention(oldCreator.id),discord.userMention(newCreator.id),discord.userMention(user.id)]))
if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"}) if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
}) })
) )
} }
+3 -3
View File
@@ -1,14 +1,14 @@
/////////////////////////////////////// ///////////////////////////////////////
//FILE BUILDERS //FILE BUILDERS
/////////////////////////////////////// ///////////////////////////////////////
import {opendiscord, api, utilities} from "../index" import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js" import * as discord from "discord.js"
const files = opendiscord.builders.files const files = opendiscord.builders.files
const lang = opendiscord.languages const lang = opendiscord.languages
const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts") const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts")
export const registerAllFiles = async () => { export async function registerAllFiles(){
transcriptFiles() transcriptFiles()
} }
@@ -17,7 +17,7 @@ const transcriptFiles = () => {
//TEXT TRANSCRIPT //TEXT TRANSCRIPT
files.add(new api.ODFile("opendiscord:text-transcript")) files.add(new api.ODFile("opendiscord:text-transcript"))
files.get("opendiscord:text-transcript").workers.add( files.get("opendiscord:text-transcript").workers.add(
new api.ODWorker("opendiscord:text-transcript",0,async (instance,params,source) => { new api.ODWorker("opendiscord:text-transcript",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,result} = params const {guild,channel,user,ticket,compiler,result} = params
const fileMode = transcriptConfig.data.textTranscriptStyle.fileMode const fileMode = transcriptConfig.data.textTranscriptStyle.fileMode

Some files were not shown because too many files have changed in this diff Show More