From dd8d5a12d63e6fdb435935ce8db3c685b2fe22b1 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Sun, 17 May 2026 22:28:23 +0200 Subject: [PATCH] Open Ticket v4.2: Config Update (JSONC) --- .github/CONTRIBUTING.md | 2 +- .github/SECURITY.md | 19 +- .tools/pterodactyl-eggs/README.md | 5 +- .../openticket-egg-v4.2.0.json | 62 +++ README.md | 2 +- config/general.json | 125 ----- config/general.jsonc | 175 ++++++ config/options.json | 126 ----- config/options.jsonc | 165 ++++++ config/panels.json | 39 -- config/panels.jsonc | 57 ++ config/questions.json | 28 - config/questions.jsonc | 102 ++++ config/transcripts.json | 55 -- config/transcripts.jsonc | 70 +++ database/states.json | 1 + index.js | 2 +- languages/arabic.json | 2 +- languages/bengali.json | 2 +- languages/catalan.json | 2 +- languages/custom.json | 2 +- languages/czech.json | 2 +- languages/danish.json | 2 +- languages/dutch.json | 2 +- languages/english.json | 2 +- languages/estonian.json | 2 +- languages/finnish.json | 2 +- languages/french.json | 2 +- languages/german.json | 2 +- languages/greek.json | 2 +- languages/hindi.json | 2 +- languages/hungarian.json | 2 +- languages/indonesian.json | 2 +- languages/italian.json | 2 +- languages/japanese.json | 2 +- languages/korean.json | 2 +- languages/kurdish.json | 2 +- languages/latvian.json | 2 +- languages/lithuanian.json | 2 +- languages/norwegian.json | 2 +- languages/persian.json | 2 +- languages/polish.json | 2 +- languages/portuguese.json | 2 +- languages/romanian.json | 2 +- languages/russian.json | 2 +- languages/simplified-chinese.json | 2 +- languages/slovenian.json | 2 +- languages/spanish.json | 2 +- languages/swedish.json | 2 +- languages/tamil.json | 2 +- languages/thai.json | 2 +- languages/traditional-chinese.json | 2 +- languages/turkish.json | 2 +- languages/ukrainian.json | 2 +- languages/vietnamese.json | 2 +- package.json | 8 +- src/actions/addTicketUser.ts | 4 +- src/actions/calculateTicketCategory.ts | 8 +- src/actions/calculateTicketName.ts | 2 +- src/actions/claimTicket.ts | 4 +- src/actions/clearTickets.ts | 2 +- src/actions/closeTicket.ts | 6 +- src/actions/createTicket.ts | 24 +- src/actions/createTicketPermissions.ts | 6 +- src/actions/deleteTicket.ts | 4 +- src/actions/moveTicket.ts | 4 +- src/actions/pinTicket.ts | 4 +- src/actions/reactionRole.ts | 4 +- src/actions/removeTicketUser.ts | 4 +- src/actions/renameTicket.ts | 4 +- src/actions/reopenTicket.ts | 6 +- src/actions/unclaimTicket.ts | 4 +- src/actions/unpinTicket.ts | 4 +- src/actions/updateTicketTopic.ts | 18 +- src/actions/utilities.ts | 10 +- src/builders/buttons.ts | 4 +- src/builders/embeds.ts | 106 ++-- src/builders/messages.ts | 32 +- src/commands/blacklist.ts | 6 +- src/commands/claim.ts | 2 +- src/commands/close.ts | 2 +- src/commands/delete.ts | 6 +- src/commands/help.ts | 2 +- src/commands/pin.ts | 2 +- src/commands/reopen.ts | 2 +- src/commands/role.ts | 2 +- src/commands/ticket.ts | 12 +- src/commands/unclaim.ts | 2 +- src/commands/unpin.ts | 2 +- src/components/verifybarModifiers.ts | 16 +- src/core/api/option.ts | 3 - src/core/cli/quickSetup.ts | 189 ++++--- src/core/main.ts | 4 +- src/core/mappings/config.ts | 291 ++++++---- src/core/mappings/fuse.ts | 10 +- src/core/startup/manageMigration.ts | 144 +++-- src/core/startup/migration.ts | 412 ++++++++++---- src/data/framework/checkerLoader.ts | 353 ++++++++---- src/data/framework/codeLoader.ts | 6 +- src/data/framework/commandLoader.ts | 10 +- src/data/framework/configLoader.ts | 512 ++++++++++++------ src/data/framework/helpMenuLoader.ts | 6 +- src/data/framework/postLoader.ts | 2 +- src/data/openticket/optionLoader.ts | 3 - src/data/openticket/panelLoader.ts | 4 +- src/index.ts | 9 +- 106 files changed, 2199 insertions(+), 1198 deletions(-) create mode 100644 .tools/pterodactyl-eggs/openticket-egg-v4.2.0.json delete mode 100644 config/general.json create mode 100644 config/general.jsonc delete mode 100644 config/options.json create mode 100644 config/options.jsonc delete mode 100644 config/panels.json create mode 100644 config/panels.jsonc delete mode 100644 config/questions.json create mode 100644 config/questions.jsonc delete mode 100644 config/transcripts.json create mode 100644 config/transcripts.jsonc create mode 100644 database/states.json diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 59c6ac0..c7cc36e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing Guidelines Open Ticket Logo -[![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!
Here you can find everything you need to know about contributing to Open Ticket.
diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 3f704b6..a381a61 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -19,18 +19,15 @@ This list will be updated on every release. | Version | Supported | Notes | |------------|-----------|---------------------------------------------------------------| -| 4.2.0 | ๐ŸŸฆ | In Development | -| 4.1.x | ๐ŸŸฆ | In Development | -| 4.1.3 | โœ… | | -| 4.1.2 | โœ… | | -| 4.1.1 | โœ… | Supported Until April 2026 (LTS) | +| 4.2.x | ๐ŸŸฆ | In Development | +| 4.2.1 | ๐ŸŸฆ | In Development | +| 4.2.0 | โœ… | | +| 4.1.3 | โœ… | (LTS) Long-Term-Support, Until September 2026 | +| 4.1.2 | ๐Ÿšง | | +| 4.1.1 | ๐Ÿšง | | | 4.1.0 | ๐Ÿšง | | -| 4.0.7 | ๐Ÿšง | | -| 4.0.6 | ๐Ÿšง | | -| 4.0.5 | ๐ŸŸง | Deprecated | -| 4.0.4 | ๐ŸŸง | Deprecated | -| < 4.0.4 | ๐ŸŸง | Deprecated, Transcripts v2.0, Documentation Only | -| < 4.0.0 | โŒ | | +| 4.0.7 | ๐ŸŸง | Deprecated | +| < 4.0.7 | โŒ | | ### ๐Ÿ•ท๏ธ Reporting Vulnerabilities You can report vulnerabilities, errors & bugs using one of the following methods: diff --git a/.tools/pterodactyl-eggs/README.md b/.tools/pterodactyl-eggs/README.md index 4585e89..c22f4a4 100644 --- a/.tools/pterodactyl-eggs/README.md +++ b/.tools/pterodactyl-eggs/README.md @@ -2,7 +2,7 @@ Open Ticket Logo [![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) [![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) - 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) - This egg will always use Open Ticket `v4.1.3`. Open Ticket updates will not have an effect on this egg. diff --git a/.tools/pterodactyl-eggs/openticket-egg-v4.2.0.json b/.tools/pterodactyl-eggs/openticket-egg-v4.2.0.json new file mode 100644 index 0000000..88530ca --- /dev/null +++ b/.tools/pterodactyl-eggs/openticket-egg-v4.2.0.json @@ -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" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index b3a38e2..16c90c3 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Related Projects:
Open Discord

Discord Invite Link -Open Ticket Version +Open Ticket Version Open Ticket Documentation Open Ticket License Open Ticket Stars diff --git a/config/general.json b/config/general.json deleted file mode 100644 index 9c39bad..0000000 --- a/config/general.json +++ /dev/null @@ -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_BOT_TOKEN (leave empty if 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":"Insert additional status 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} - } - } -} \ No newline at end of file diff --git a/config/general.jsonc b/config/general.jsonc new file mode 100644 index 0000000..ec0c4ba --- /dev/null +++ b/config/general.jsonc @@ -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" + } +} \ No newline at end of file diff --git a/config/options.json b/config/options.json deleted file mode 100644 index 331864a..0000000 --- a/config/options.json +++ /dev/null @@ -1,126 +0,0 @@ -[ - { - "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":{ - "emoji":"๐ŸŽซ (leave empty to disable)", - "label":"question (leave empty to disable)", - "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 (leave empty to disable)", - "closedCategory":"category id (leave empty to disable)", - "backupCategory":"category id (leave empty to disable)", - "claimedCategory":[ - {"user":"USER_ID","category":"CATEGORY_ID"} - ], - "topic":"This is the ticket topic shown in the channel. (leave empty to disable)" - }, - - "dmMessage":{ - "enabled":false, - "text":"", - "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 disable)", - - "image":"https://www.example.com/image.png (leave empty to disable)", - "thumbnail":"https://www.example.com/image.png (leave empty to disable)", - "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 ticket in our server.\nOur support team will assist you as soon as possible. (leave empty to disable)", - "customColor":"#f8ab00 (leave empty to disable)", - - "image":"https://www.example.com/image.png (leave empty to disable)", - "thumbnail":"https://www.example.com/image.png (leave empty to disable)", - "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":"Take a look at our amazing website by clicking the button.", - "type":"website", - - "button":{ - "emoji":"๐Ÿ˜ƒ", - "label":"Visit Website" - }, - - "url":"https://www.dj-dj.be" - }, - { - "id":"example-role", - "name":"Update Ping", - "description":"Click here to receive notifications about 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 - } -] \ No newline at end of file diff --git a/config/options.jsonc b/config/options.jsonc new file mode 100644 index 0000000..1948f6e --- /dev/null +++ b/config/options.jsonc @@ -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) + } +] \ No newline at end of file diff --git a/config/panels.json b/config/panels.json deleted file mode 100644 index 20faddd..0000000 --- a/config/panels.json +++ /dev/null @@ -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 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.", - - "customColor":"#f8ab00 (leave empty to disable)", - "url":"https://openticket.dj-dj.be (leave empty to disable)", - - "image":"https://www.example.com/image.png (leave empty to disable)", - "thumbnail":"https://www.example.com/image.png (leave empty to disable)", - - "footer":"Open Ticket v4.1.3 (leave empty to disable)", - "fields":[ - {"name":"Field name","value":"Field value","inline":false} - ], - "timestamp":false - }, - "settings":{ - "dropdownPlaceholder":"Choose a ticket type", - - "enableMaxTicketsWarningInText":false, - "enableMaxTicketsWarningInEmbed":true, - - "describeOptionsLayout":"simple OR normal OR detailed", - "describeOptionsCustomTitle":"", - "describeOptionsInText":false, - "describeOptionsInEmbedFields":true, - "describeOptionsInEmbedDescription":false - } - } -] \ No newline at end of file diff --git a/config/panels.jsonc b/config/panels.jsonc new file mode 100644 index 0000000..cf5bca8 --- /dev/null +++ b/config/panels.jsonc @@ -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 + * + * 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 + } + } +] \ No newline at end of file diff --git a/config/questions.json b/config/questions.json deleted file mode 100644 index 3d36da9..0000000 --- a/config/questions.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "id":"example-question-1", - "name":"Example Question 1", - "type":"short", - - "required":true, - "placeholder":"An example short text question.", - "length":{ - "enabled":false, - "min":0, - "max":1000 - } - }, - { - "id":"example-question-2", - "name":"Example Question 2", - "type":"paragraph", - - "required":false, - "placeholder":"An example paragraph text question.", - "length":{ - "enabled":false, - "min":0, - "max":1000 - } - } -] \ No newline at end of file diff --git a/config/questions.jsonc b/config/questions.jsonc new file mode 100644 index 0000000..8f9062e --- /dev/null +++ b/config/questions.jsonc @@ -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." + } +] \ No newline at end of file diff --git a/config/transcripts.json b/config/transcripts.json deleted file mode 100644 index bd01a59..0000000 --- a/config/transcripts.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "general":{ - "enabled":false, - - "enableChannel":false, - "enableCreatorDM":false, - "enableParticipantDM":false, - "enableActiveAdminDM":false, - "enableEveryAdminDM":false, - - "channel":"DISCORD_TRANSCRIPT_CHANNEL_ID (leave empty to disable)", - "mode":"html OR text" - }, - "embedSettings":{ - "customColor":"#f8ab00 (leave empty to disable)", - "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":"transcript" - }, - "htmlTranscriptStyle":{ - "background":{ - "enableCustomBackground":false, - "backgroundColor":"#f8ba00 (leave empty to disable)", - "backgroundImage":"https://www.example.com/image.png (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" - } - } -} \ No newline at end of file diff --git a/config/transcripts.jsonc b/config/transcripts.jsonc new file mode 100644 index 0000000..2a441c5 --- /dev/null +++ b/config/transcripts.jsonc @@ -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" + } + } +} \ No newline at end of file diff --git a/database/states.json b/database/states.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/database/states.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/index.js b/index.js index 1c05e7d..2935154 100644 --- a/index.js +++ b/index.js @@ -13,7 +13,7 @@ const flags = [ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•šโ•โ• - v4.1.3 - Made by DJj123dj & Contributors + v4.2.0 - Made by DJj123dj & Contributors Discord: https://discord.dj-dj.be Docs: https://otdocs.dj-dj.be diff --git a/languages/arabic.json b/languages/arabic.json index 694bf33..40c7cff 100644 --- a/languages/arabic.json +++ b/languages/arabic.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["palestinian"], "lastedited":"16/02/2026", "language":"Arabic", diff --git a/languages/bengali.json b/languages/bengali.json index fe5894f..317f3d5 100644 --- a/languages/bengali.json +++ b/languages/bengali.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["HanumeshGupta"], "lastedited":"16/02/2026", "language":"Bengali", diff --git a/languages/catalan.json b/languages/catalan.json index 1336d34..fed41c0 100644 --- a/languages/catalan.json +++ b/languages/catalan.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["guillee3"], "lastedited":"16/02/2026", "language":"Catalan", diff --git a/languages/custom.json b/languages/custom.json index ce7acda..f22936f 100644 --- a/languages/custom.json +++ b/languages/custom.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["DJj123dj"], "lastedited":"16/02/2026", "language":"Custom", diff --git a/languages/czech.json b/languages/czech.json index ef4a93a..03b8bc3 100644 --- a/languages/czech.json +++ b/languages/czech.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["spyeye_"], "lastedited":"16/02/2026", "language":"Czech", diff --git a/languages/danish.json b/languages/danish.json index 4f93fed..ab42fd0 100644 --- a/languages/danish.json +++ b/languages/danish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["the_gamer"], "lastedited":"16/02/2026", "language":"Danish", diff --git a/languages/dutch.json b/languages/dutch.json index f13ddfc..9c19866 100644 --- a/languages/dutch.json +++ b/languages/dutch.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["DJj123dj"], "lastedited":"16/02/2026", "language":"Dutch", diff --git a/languages/english.json b/languages/english.json index ed96bb2..7244893 100644 --- a/languages/english.json +++ b/languages/english.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["DJj123dj"], "lastedited":"16/02/2026", "language":"English", diff --git a/languages/estonian.json b/languages/estonian.json index 241bfec..1225d79 100644 --- a/languages/estonian.json +++ b/languages/estonian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["iamnotmega","ChatGPT"], "lastedited":"16/02/2026", "language":"Estonian", diff --git a/languages/finnish.json b/languages/finnish.json index d922108..895a1bf 100644 --- a/languages/finnish.json +++ b/languages/finnish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["iamnotmega","ChatGPT"], "lastedited":"16/02/2026", "language":"Finnish", diff --git a/languages/french.json b/languages/french.json index d50f971..38b582f 100644 --- a/languages/french.json +++ b/languages/french.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["guillee3"], "lastedited":"16/02/2026", "language":"French", diff --git a/languages/german.json b/languages/german.json index 1a9b112..0c8e1c4 100644 --- a/languages/german.json +++ b/languages/german.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["benzorich"], "lastedited":"16/02/2026", "language":"German", diff --git a/languages/greek.json b/languages/greek.json index 998e304..bc11230 100644 --- a/languages/greek.json +++ b/languages/greek.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"16/02/2026", "language":"Greek", diff --git a/languages/hindi.json b/languages/hindi.json index 30dd621..0addf7e 100644 --- a/languages/hindi.json +++ b/languages/hindi.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["challenger_nova"], "lastedited":"16/02/2026", "language":"Hindi", diff --git a/languages/hungarian.json b/languages/hungarian.json index bf989b3..7908d10 100644 --- a/languages/hungarian.json +++ b/languages/hungarian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["Kornel0706"], "lastedited":"16/02/2026", "language":"Hungarian", diff --git a/languages/indonesian.json b/languages/indonesian.json index 66c1483..7ea791d 100644 --- a/languages/indonesian.json +++ b/languages/indonesian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["erxg"], "lastedited":"16/02/2026", "language":"Indonesian", diff --git a/languages/italian.json b/languages/italian.json index 28a6723..e7be54b 100644 --- a/languages/italian.json +++ b/languages/italian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["fraden1mvp.","imperatorix_17"], "lastedited":"16/02/2026", "language":"Italian", diff --git a/languages/japanese.json b/languages/japanese.json index f528a9a..ad91014 100644 --- a/languages/japanese.json +++ b/languages/japanese.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"16/02/2026", "language":"Japanese", diff --git a/languages/korean.json b/languages/korean.json index 00e2d6b..17234c6 100644 --- a/languages/korean.json +++ b/languages/korean.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"16/02/2026", "language":"Korean", diff --git a/languages/kurdish.json b/languages/kurdish.json index 0b14b78..be9547e 100644 --- a/languages/kurdish.json +++ b/languages/kurdish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"16/02/2026", "language":"Kurdish", diff --git a/languages/latvian.json b/languages/latvian.json index 859e8ce..16755a1 100644 --- a/languages/latvian.json +++ b/languages/latvian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["NoOneNook"], "lastedited":"16/02/2026", "language":"Latvian", diff --git a/languages/lithuanian.json b/languages/lithuanian.json index ba21919..9c32861 100644 --- a/languages/lithuanian.json +++ b/languages/lithuanian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["TsgIndrius"], "lastedited":"16/02/2026", "language":"Lithuanian", diff --git a/languages/norwegian.json b/languages/norwegian.json index 42b6ff5..a87a119 100644 --- a/languages/norwegian.json +++ b/languages/norwegian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["NoOneNook"], "lastedited":"16/02/2026", "language":"Norwegian", diff --git a/languages/persian.json b/languages/persian.json index f262ff9..2d79b24 100644 --- a/languages/persian.json +++ b/languages/persian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["dysashop","zhavis"], "lastedited":"16/02/2026", "language":"Persian", diff --git a/languages/polish.json b/languages/polish.json index ae3bcc9..b30c1c0 100644 --- a/languages/polish.json +++ b/languages/polish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["DanoGlez"], "lastedited":"16/02/2026", "language":"Polish", diff --git a/languages/portuguese.json b/languages/portuguese.json index 182a73d..3e3ad64 100644 --- a/languages/portuguese.json +++ b/languages/portuguese.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["quiradon"], "lastedited":"16/02/2026", "language":"Portuguese", diff --git a/languages/romanian.json b/languages/romanian.json index 36e26ee..3521dc7 100644 --- a/languages/romanian.json +++ b/languages/romanian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["SankeDev"], "lastedited":"16/02/2026", "language":"Romanian", diff --git a/languages/russian.json b/languages/russian.json index adc1081..16e833c 100644 --- a/languages/russian.json +++ b/languages/russian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["NoOneNook"], "lastedited":"16/02/2026", "language":"Russian", diff --git a/languages/simplified-chinese.json b/languages/simplified-chinese.json index 07457d7..4d1564c 100644 --- a/languages/simplified-chinese.json +++ b/languages/simplified-chinese.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"16/02/2026", "language":"Simplified Chainese", diff --git a/languages/slovenian.json b/languages/slovenian.json index 6ec6988..305d3e4 100644 --- a/languages/slovenian.json +++ b/languages/slovenian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"16/02/2026", "language":"Solvenian", diff --git a/languages/spanish.json b/languages/spanish.json index f9d7335..cf15d56 100644 --- a/languages/spanish.json +++ b/languages/spanish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["Redactado","Josuens"], "lastedited":"16/02/2026", "language":"Spanish", diff --git a/languages/swedish.json b/languages/swedish.json index d71f506..15571cc 100644 --- a/languages/swedish.json +++ b/languages/swedish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["NoOneNook"], "lastedited":"16/02/2026", "language":"Svenska", diff --git a/languages/tamil.json b/languages/tamil.json index 0a52857..9b68dc7 100644 --- a/languages/tamil.json +++ b/languages/tamil.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"16/02/2026", "language":"Tamil", diff --git a/languages/thai.json b/languages/thai.json index 71f1294..f2b4b6a 100644 --- a/languages/thai.json +++ b/languages/thai.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["modshd"], "lastedited":"16/02/2026", "language":"Thai", diff --git a/languages/traditional-chinese.json b/languages/traditional-chinese.json index 21fd839..d44f21c 100644 --- a/languages/traditional-chinese.json +++ b/languages/traditional-chinese.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["me.october"], "lastedited":"10/03/2026", "language":"Traditional Chinese", diff --git a/languages/turkish.json b/languages/turkish.json index ee66fc5..09e949b 100644 --- a/languages/turkish.json +++ b/languages/turkish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["palestinian"], "lastedited":"16/02/2026", "language":"Turkish", diff --git a/languages/ukrainian.json b/languages/ukrainian.json index 416da30..c1c2a19 100644 --- a/languages/ukrainian.json +++ b/languages/ukrainian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["Anderskiy"], "lastedited":"16/02/2026", "language":"Ukrainian", diff --git a/languages/vietnamese.json b/languages/vietnamese.json index 12d6318..24f43c0 100644 --- a/languages/vietnamese.json +++ b/languages/vietnamese.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.3", + "otversion":"v4.2.0", "translators":["ngocdiep2006"], "lastedited":"16/02/2026", "language":"Vietnamese", diff --git a/package.json b/package.json index 75330b8..027eed9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "open-ticket", "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! ", "keywords": [ "ticket-bot", @@ -26,12 +26,12 @@ "license": "GPL-3.0-only", "dependencies": { "@discordjs/rest": "^2.6.1", - "@open-discord-bots/framework": "^0.4.0", + "@open-discord-bots/framework": "^0.4.2", "@types/node": "^22.5.0", "@types/terminal-kit": "^2.5.7", "ansis": "^4.2.0", - "discord.js": "^14.26.3", - "formatted-json-stringify": "^1.3.1", + "discord.js": "^14.26.4", + "formatted-json-stringify": "^1.3.2", "terminal-kit": "^3.1.2", "typescript": "^6.0.3" }, diff --git a/src/actions/addTicketUser.ts b/src/actions/addTicketUser.ts index ac91b5c..27da7ce 100644 --- a/src/actions/addTicketUser.ts +++ b/src/actions/addTicketUser.ts @@ -49,14 +49,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason,data} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket,data} = params diff --git a/src/actions/calculateTicketCategory.ts b/src/actions/calculateTicketCategory.ts index cd75bb9..dcc2c49 100644 --- a/src/actions/calculateTicketCategory.ts +++ b/src/actions/calculateTicketCategory.ts @@ -46,8 +46,9 @@ export async function registerActions(){ 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 = option.get("opendiscord:channel-category-closed").value + const closeCategoryId = generalConfig.data.ticketSystem.closedCategory.categoryId if (!closeCategoryId) return const closeCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,closeCategoryId) if (closeCategory){ @@ -74,7 +75,7 @@ export async function registerActions(){ if (!ticket) return if (!ticket.get("opendiscord:claimed").value) return - const claimedCategoryIds = option.get("opendiscord:channel-categories-claimed").value + 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) @@ -101,8 +102,9 @@ export async function registerActions(){ 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 = option.get("opendiscord:channel-category-backup").value + const backupCategoryId = generalConfig.data.ticketSystem.backupCategory.categoryId if (!backupCategoryId) return const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,backupCategoryId) if (backupCategory){ diff --git a/src/actions/calculateTicketName.ts b/src/actions/calculateTicketName.ts index 2c98def..f6d1777 100644 --- a/src/actions/calculateTicketName.ts +++ b/src/actions/calculateTicketName.ts @@ -19,7 +19,7 @@ export async function registerActions(){ const baseChannelName = (channelRenamed) ? channelRenamed : channelPrefix+channelSuffix //calculate status emojis - const pinEmoji = (ticket && ticket.get("opendiscord:pinned").value) ? generalConfig.data.system.pinEmoji : "" + 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 diff --git a/src/actions/claimTicket.ts b/src/actions/claimTicket.ts index b9ca1de..e6a8c79 100644 --- a/src/actions/claimTicket.ts +++ b/src/actions/claimTicket.ts @@ -73,14 +73,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket} = params diff --git a/src/actions/clearTickets.ts b/src/actions/clearTickets.ts index 4e75d1f..3c15e2b 100644 --- a/src/actions/clearTickets.ts +++ b/src/actions/clearTickets.ts @@ -47,7 +47,7 @@ export async function registerActions(){ const {guild,channel,user,filter,list} = params //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") if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:clear-logs").build(origin,{guild,channel,user,filter,list:instance.list ?? []})) } diff --git a/src/actions/closeTicket.ts b/src/actions/closeTicket.ts index c405fc1..0c1e959 100644 --- a/src/actions/closeTicket.ts +++ b/src/actions/closeTicket.ts @@ -99,7 +99,7 @@ export async function registerActions(){ ticket.get("opendiscord:participants").value.forEach((participant) => { //all participants that aren't roles/admins => readonly (OR non-viewable when enabled) if (participant.type == "user"){ - if (generalConfig.data.system.removeParticipantsOnClose) permissions.push({ + if (generalConfig.data.ticketSystem.removeParticipantsOnClose) permissions.push({ type:discord.OverwriteType.Member, id:participant.id, allow:[], @@ -138,14 +138,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket} = params diff --git a/src/actions/createTicket.ts b/src/actions/createTicket.ts index 68f2e89..c8ff9ca 100644 --- a/src/actions/createTicket.ts +++ b/src/actions/createTicket.ts @@ -91,15 +91,15 @@ export async function registerActions(){ //handle channel topic const channelTopics: string[] = [] - if (generalConfig.data.system.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.system.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.system.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.system.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.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.showOptionName) channelTopics.push(option.get("opendiscord:name").value) + if (generalConfig.data.ticketSystem.channelTopic.showOptionDescription) channelTopics.push(option.get("opendiscord:description").value) + if (generalConfig.data.ticketSystem.channelTopic.showOptionTopic) channelTopics.push(channelTopicText) + if (generalConfig.data.ticketSystem.channelTopic.showPriority) channelTopics.push("**"+lang.getTranslation("params.uppercase.priority")+":** "+opendiscord.priorities.get("opendiscord:none").renderDisplayName()) + if (generalConfig.data.ticketSystem.channelTopic.showClosed) channelTopics.push("**"+lang.getTranslation("params.uppercase.status")+":** "+lang.getTranslation("params.uppercase.open")) + if (generalConfig.data.ticketSystem.channelTopic.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+lang.getTranslation("params.uppercase.noone")) + if (generalConfig.data.ticketSystem.channelTopic.showPinned) channelTopics.push("**"+lang.getTranslation("params.uppercase.pinned")+":** "+lang.getTranslation("params.uppercase.no")) + if (generalConfig.data.ticketSystem.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(user.id)) + 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 const channel = await guild.channels.create({ @@ -192,7 +192,7 @@ export async function registerActions(){ ticket.get("opendiscord:ticket-message").value = ticketMsg.id //pin ticket message (if required) - if (generalConfig.data.system.pinFirstTicketMessage && ticketMsg.pinnable) await ticketMsg.pin("Ticket Message") + if (generalConfig.data.ticketSystem.pinFirstTicketMessage && ticketMsg.pinnable) await ticketMsg.pin("Ticket Message") //manage stats await opendiscord.statistics.get("opendiscord:ticket").setStat("opendiscord:messages-sent",ticket.id.value,1,"increase") @@ -212,13 +212,13 @@ export async function registerActions(){ if (!ticket || !channel) return opendiscord.log("Ticket Creation Error: Unable to send ticket message. Previous worker failed!","error") //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") if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-logs").build(origin,{guild,channel,user,ticket})) } //to dm - if (generalConfig.data.system.messages.creation.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-dm").build(origin,{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,origin,cancel) => { const {guild,user,answers,option} = params diff --git a/src/actions/createTicketPermissions.ts b/src/actions/createTicketPermissions.ts index 39daa1b..0617124 100644 --- a/src/actions/createTicketPermissions.ts +++ b/src/actions/createTicketPermissions.ts @@ -38,14 +38,14 @@ export async function registerActions(){ }), new api.ODWorker("opendiscord:check-global-limits",2,(instance,params,origin,cancel) => { 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 globalTicketCount = allTickets.length const userTickets = opendiscord.tickets.getFiltered((ticket) => ticket.exists("opendiscord:opened-by") && (ticket.get("opendiscord:opened-by").value == params.user.id)) const userTicketCount = userTickets.length - if (globalTicketCount >= generalConfig.data.system.limits.globalMaximum){ + if (globalTicketCount >= generalConfig.data.ticketSystem.limits.globalMaximum){ instance.valid = false instance.reason = "global-limit" opendiscord.log(params.user.displayName+" tried to create a ticket but reached the limit!","info",[ @@ -55,7 +55,7 @@ export async function registerActions(){ {key:"limit",value:"global"} ]) return cancel() - }else if (userTicketCount >= generalConfig.data.system.limits.userMaximum){ + }else if (userTicketCount >= generalConfig.data.ticketSystem.limits.userMaximum){ instance.valid = false instance.reason = "global-user-limit" opendiscord.log(params.user.displayName+" tried to create a ticket, but reached the limit!","info",[ diff --git a/src/actions/deleteTicket.ts b/src/actions/deleteTicket.ts index c6cc4ce..500ab61 100644 --- a/src/actions/deleteTicket.ts +++ b/src/actions/deleteTicket.ts @@ -60,14 +60,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket,reason} = params diff --git a/src/actions/moveTicket.ts b/src/actions/moveTicket.ts index 30ce42b..2679368 100644 --- a/src/actions/moveTicket.ts +++ b/src/actions/moveTicket.ts @@ -140,14 +140,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason,data} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket} = params diff --git a/src/actions/pinTicket.ts b/src/actions/pinTicket.ts index 551b0fd..6d52953 100644 --- a/src/actions/pinTicket.ts +++ b/src/actions/pinTicket.ts @@ -73,14 +73,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket} = params diff --git a/src/actions/reactionRole.ts b/src/actions/reactionRole.ts index 5460ecf..8a0a116 100644 --- a/src/actions/reactionRole.ts +++ b/src/actions/reactionRole.ts @@ -88,13 +88,13 @@ export async function registerActions(){ if (!instance.role || !instance.result) return //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") 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 - if (generalConfig.data.system.messages.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})) + 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,origin,cancel) => { const {guild,user,option} = params diff --git a/src/actions/removeTicketUser.ts b/src/actions/removeTicketUser.ts index 5f91be8..93737fc 100644 --- a/src/actions/removeTicketUser.ts +++ b/src/actions/removeTicketUser.ts @@ -44,14 +44,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason,data} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket,data} = params diff --git a/src/actions/renameTicket.ts b/src/actions/renameTicket.ts index ff552a1..7ffd071 100644 --- a/src/actions/renameTicket.ts +++ b/src/actions/renameTicket.ts @@ -52,14 +52,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason,data} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket} = params diff --git a/src/actions/reopenTicket.ts b/src/actions/reopenTicket.ts index 361f9fc..75d06da 100644 --- a/src/actions/reopenTicket.ts +++ b/src/actions/reopenTicket.ts @@ -29,7 +29,7 @@ export async function registerActions(){ ticket.get("opendiscord:open").value = true ticket.get("opendiscord:busy").value = true - if (generalConfig.data.system.disableAutocloseAfterReopen){ + if (generalConfig.data.ticketSystem.disableAutocloseAfterReopen){ //disable autoclose after reopen ticket.get("opendiscord:autoclose-enabled").value = false ticket.get("opendiscord:autoclose-hours").value = 0 @@ -136,14 +136,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket} = params diff --git a/src/actions/unclaimTicket.ts b/src/actions/unclaimTicket.ts index 3f01cd8..e91b4ef 100644 --- a/src/actions/unclaimTicket.ts +++ b/src/actions/unclaimTicket.ts @@ -69,14 +69,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket} = params diff --git a/src/actions/unpinTicket.ts b/src/actions/unpinTicket.ts index b1299c5..747754a 100644 --- a/src/actions/unpinTicket.ts +++ b/src/actions/unpinTicket.ts @@ -64,14 +64,14 @@ export async function registerActions(){ const {guild,channel,user,ticket,reason} = params //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") 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 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(origin,{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,origin,cancel) => { const {guild,channel,user,ticket} = params diff --git a/src/actions/updateTicketTopic.ts b/src/actions/updateTicketTopic.ts index 816cc1c..207a5d7 100644 --- a/src/actions/updateTicketTopic.ts +++ b/src/actions/updateTicketTopic.ts @@ -29,15 +29,15 @@ export async function registerActions(){ //handle channel topic const channelTopics: string[] = [] - if (generalConfig.data.system.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.system.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.system.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.system.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.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.showOptionName) channelTopics.push(ticket.option.get("opendiscord:name").value) + if (generalConfig.data.ticketSystem.channelTopic.showOptionDescription) channelTopics.push(ticket.option.get("opendiscord:description").value) + if (generalConfig.data.ticketSystem.channelTopic.showOptionTopic) channelTopics.push(ticket.get("opendiscord:topic").value) + 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.ticketSystem.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.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+(claimedBy ? discord.userMention(claimedBy) : lang.getTranslation("params.uppercase.noone"))) + 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.ticketSystem.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(creator)) + 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 channel.setTopic(channelTopics.join(" โ€ข "),"Topic Changed") diff --git a/src/actions/utilities.ts b/src/actions/utilities.ts index 4caa08b..8f87003 100644 --- a/src/actions/utilities.ts +++ b/src/actions/utilities.ts @@ -29,7 +29,7 @@ export async function replyHasPermissions(instance:api.ODButtonResponderInstance //check permissions const {user,member,channel,guild} = instance const generalConfig = opendiscord.configs.get("opendiscord:general") - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions[commandName],"support",user,member,channel,guild,settings) + 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})) @@ -139,18 +139,18 @@ export async function replyMessageMustBeSentBeforeClose(instance:api.ODButtonRes 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.system.permissions[commandName],"support",user,member,channel,guild) + 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.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){ + 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.system.allowCloseBeforeMessage && analysis.totalMessages < 1){ + 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.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){ + 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 } diff --git a/src/builders/buttons.ts b/src/builders/buttons.ts index db6d4ae..b4ae6cd 100644 --- a/src/builders/buttons.ts +++ b/src/builders/buttons.ts @@ -255,7 +255,7 @@ const ticketButtons = () => { instance.setMode("button") instance.setCustomId("od:pin-ticket") instance.setColor("gray") - instance.setEmoji(generalConfig.data.system.pinEmoji) + instance.setEmoji(generalConfig.data.ticketSystem.pinEmoji) instance.setLabel(lang.getTranslation("actions.buttons.pin")) }) ) @@ -269,7 +269,7 @@ const ticketButtons = () => { instance.setMode("button") instance.setCustomId("od:unpin-ticket") instance.setColor("gray") - instance.setEmoji(generalConfig.data.system.pinEmoji) + instance.setEmoji(generalConfig.data.ticketSystem.pinEmoji) instance.setLabel(lang.getTranslation("actions.buttons.unpin")) }) ) diff --git a/src/builders/embeds.ts b/src/builders/embeds.ts index df686db..c8e7f7e 100644 --- a/src/builders/embeds.ts +++ b/src/builders/embeds.ts @@ -42,7 +42,7 @@ const errorEmbeds = () => { 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.setAuthor(user.displayName,user.displayAvatarURL()) 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(" ")+"**" - 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.setAuthor(user.displayName,user.displayAvatarURL()) 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 == "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.setAuthor(user.displayName,user.displayAvatarURL()) 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) => { 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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslation("errors.descriptions.unknownCommand")) @@ -169,7 +169,7 @@ const errorEmbeds = () => { else if (perm == "discord-administrator") return "- "+lang.getTranslation("errors.permissions.discord-administrator") }).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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissions",[method])) @@ -185,7 +185,7 @@ const errorEmbeds = () => { 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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissionsCooldown",[method])) @@ -201,7 +201,7 @@ const errorEmbeds = () => { 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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissionsBlacklist",[method])) @@ -214,7 +214,7 @@ const errorEmbeds = () => { new api.ODWorker("opendiscord:error-no-permissions-limits",0,async (instance,params,origin) => { 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.setAuthor(user.displayName,user.displayAvatarURL()) if (limit == "global") instance.setDescription(lang.getTranslation("errors.descriptions.noPermissionsLimitGlobal")) @@ -232,7 +232,7 @@ const errorEmbeds = () => { 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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.internalError",[method])) @@ -247,7 +247,7 @@ const errorEmbeds = () => { new api.ODWorker("opendiscord:error-ticket-unknown",0,async (instance,params,origin) => { 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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslation("errors.descriptions.unknownTicket")) @@ -261,7 +261,7 @@ const errorEmbeds = () => { new api.ODWorker("opendiscord:error-ticket-deprecated",0,async (instance,params,origin) => { 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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslation("errors.descriptions.deprecatedTicket")) @@ -281,7 +281,7 @@ const errorEmbeds = () => { }else return "- `"+option.id.value+"`" }).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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setFooter(lang.getTranslation("errors.descriptions.askForInfo")) @@ -301,7 +301,7 @@ const errorEmbeds = () => { }else return "- `"+panel.id.value+"`" }).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.setAuthor(user.displayName,user.displayAvatarURL()) instance.addFields({name:lang.getTranslation("params.uppercase.validPanels")+":",value:renderedPanels}) @@ -317,7 +317,7 @@ const errorEmbeds = () => { 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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.notInGuild",[method])) @@ -332,7 +332,7 @@ const errorEmbeds = () => { 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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslation("errors.descriptions.channelRename")) @@ -352,7 +352,7 @@ const errorEmbeds = () => { 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.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor) + 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()) @@ -376,7 +376,7 @@ const errorEmbeds = () => { 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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslationWithParams("errors.descriptions.busy",[method])) @@ -501,7 +501,7 @@ const statsEmbeds = () => { new api.ODWorker("opendiscord:stats-ticket-unknown",0,async (instance,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.setAuthor(user.displayName,user.displayAvatarURL()) instance.setDescription(lang.getTranslationWithParams("actions.descriptions.statsError",[discord.channelMention(id)])) @@ -534,8 +534,8 @@ const panelEmbeds = () => { instance.setDescription(embedOptions.description) } - if (panel.get("opendiscord:enable-max-tickets-warning-embed").value && generalConfig.data.system.limits.enabled){ - instance.setDescription(instance.data.description+"\n\n*"+lang.getTranslationWithParams("actions.descriptions.ticketMessageLimit",[generalConfig.data.system.limits.userMaximum.toString()])+"*") + 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.ticketSystem.limits.userMaximum.toString()])+"*") } if (panel.get("opendiscord:describe-options-in-embed-fields").value){ @@ -623,12 +623,12 @@ const ticketEmbeds = () => { if (ticket.option.get("opendiscord:questions").value.length > 0){ //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 answers.forEach((answer) => { if (!answer.value || answer.value.length == 0) return - if (generalConfig.data.system.questionFieldsInCodeBlock) instance.addFields({name:answer.name,value:"```"+answer.value.slice(0,1024-6)+"```",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 if (embedOptions.fields){ @@ -656,7 +656,7 @@ const ticketEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿ”’",lang.getTranslation("actions.titles.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 ?? "/")+"```"}) }) ) @@ -670,7 +670,7 @@ const ticketEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿ”“",lang.getTranslation("actions.titles.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 ?? "/")+"```"}) }) ) @@ -684,7 +684,7 @@ const ticketEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿ—‘๏ธ",lang.getTranslation("actions.titles.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 ?? "/")+"```"}) }) ) @@ -698,7 +698,7 @@ const ticketEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿ‘‹",lang.getTranslation("actions.titles.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 ?? "/")+"```"}) }) ) @@ -712,7 +712,7 @@ const ticketEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("โ†ฉ๏ธ",lang.getTranslation("actions.titles.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 ?? "/")+"```"}) }) ) @@ -724,9 +724,9 @@ const ticketEmbeds = () => { instance.setAuthor(user.displayName,user.displayAvatarURL()) 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")) - 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 ?? "/")+"```"}) }) ) @@ -738,9 +738,9 @@ const ticketEmbeds = () => { instance.setAuthor(user.displayName,user.displayAvatarURL()) 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")) - 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 ?? "/")+"```"}) }) ) @@ -754,7 +754,7 @@ const ticketEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿ”„",lang.getTranslation("actions.titles.rename"))) 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 ?? "/")+"```"}) }) ) @@ -768,7 +768,7 @@ const ticketEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿ”€",lang.getTranslation("actions.titles.move"))) 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 ?? "/")+"```"}) }) ) @@ -782,7 +782,7 @@ const ticketEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿ‘ค",lang.getTranslation("actions.titles.add"))) 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 ?? "/")+"```"}) }) ) @@ -796,7 +796,7 @@ const ticketEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿ‘ค",lang.getTranslation("actions.titles.remove"))) 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 ?? "/")+"```"}) }) ) @@ -828,10 +828,10 @@ const ticketEmbeds = () => { instance.setTitle(utilities.emojiTitle("โ†ฉ๏ธ",lang.getTranslation("actions.titles.unclaim"))) instance.setDescription(lang.getTranslation("actions.logs.unclaimDm")) }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")) }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")) }else if (mode == "rename"){ instance.setTitle(utilities.emojiTitle("๐Ÿ”„",lang.getTranslation("actions.titles.rename"))) @@ -864,7 +864,7 @@ const ticketEmbeds = () => { {name:lang.getTranslation("params.uppercase.ticket")+":",value:"```#"+(channel ? channel.name : "")+"```",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"){ instance.setTitle(utilities.emojiTitle("๐Ÿ”’",lang.getTranslation("actions.titles.close"))) @@ -882,10 +882,10 @@ const ticketEmbeds = () => { instance.setTitle(utilities.emojiTitle("โ†ฉ๏ธ",lang.getTranslation("actions.titles.unclaim"))) instance.setDescription(lang.getTranslationWithParams("actions.logs.unclaimLog",[discord.userMention(user.id)])) }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)])) }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)])) }else if (mode == "rename"){ instance.setTitle(utilities.emojiTitle("๐Ÿ”„",lang.getTranslation("actions.titles.rename"))) @@ -938,7 +938,7 @@ const blacklistEmbeds = () => { if (blacklist){ 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)])+"*") }) @@ -954,7 +954,7 @@ const blacklistEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿšซ",lang.getTranslation("actions.titles.blacklistAdd"))) 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 ?? "/")+"```"}) }) ) @@ -968,7 +968,7 @@ const blacklistEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿ†“",lang.getTranslation("actions.titles.blacklistRemove"))) 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 ?? "/")+"```"}) }) ) @@ -985,7 +985,7 @@ const blacklistEmbeds = () => { instance.setTitle(utilities.emojiTitle((mode == "add") ? "๐Ÿšซ" : "๐Ÿ†“",title)) instance.setTimestamp(new Date()) 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 ?? "/")+"```"}) }) ) @@ -1004,7 +1004,7 @@ const blacklistEmbeds = () => { instance.setAuthor(user.displayName,user.displayAvatarURL()) instance.setTimestamp(new Date()) 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 ?? "/")+"```"}) }) ) } @@ -1103,12 +1103,12 @@ const transcriptEmbeds = () => { new api.ODWorker("opendiscord:transcript-error",0,async (instance,params,origin) => { 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.setTimestamp(new Date()) instance.setDescription(lang.getTranslation("transcripts.errors.error")) 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 ?? "/")+"```"}) }) ) } @@ -1289,7 +1289,7 @@ const autoEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("โฑ๏ธ",lang.getTranslation("actions.titles.autocloseEnabled"))) 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 ?? "/")+"```"}) }) ) @@ -1303,7 +1303,7 @@ const autoEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("โฑ๏ธ",lang.getTranslation("actions.titles.autodeleteEnabled"))) 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 ?? "/")+"```"}) }) ) @@ -1317,7 +1317,7 @@ const autoEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("โฑ๏ธ",lang.getTranslation("actions.titles.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 ?? "/")+"```"}) }) ) @@ -1331,7 +1331,7 @@ const autoEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("โฑ๏ธ",lang.getTranslation("actions.titles.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 ?? "/")+"```"}) }) ) } @@ -1361,7 +1361,7 @@ const extraEmbeds = () => { instance.setColor(generalConfig.data.mainColor) instance.setTitle(utilities.emojiTitle("๐Ÿšจ",lang.getTranslation("actions.titles.prioritySet"))) 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 ?? "/")+"```"}) }) ) @@ -1388,7 +1388,7 @@ const extraEmbeds = () => { instance.setColor(generalConfig.data.mainColor) 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)])) - 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 ?? "/")+"```"}) }) ) } \ No newline at end of file diff --git a/src/builders/messages.ts b/src/builders/messages.ts index e974882..7b49b23 100644 --- a/src/builders/messages.ts +++ b/src/builders/messages.ts @@ -286,8 +286,8 @@ const panelMessages = () => { instance.setContent(text) } - if (panel.get("opendiscord:enable-max-tickets-warning-text").value && generalConfig.data.system.limits.enabled){ - instance.setContent(instance.data.content+"\n\n*"+lang.getTranslationWithParams("actions.descriptions.ticketMessageLimit",[generalConfig.data.system.limits.userMaximum.toString()])+"*") + if (panel.get("opendiscord:enable-max-tickets-warning-text").value && generalConfig.data.ticketSystem.limits.enabled){ + instance.setContent(instance.data.content+"\n\n*"+lang.getTranslationWithParams("actions.descriptions.ticketMessageLimit",[generalConfig.data.ticketSystem.limits.userMaximum.toString()])+"*") } //add embed @@ -399,7 +399,7 @@ const ticketMessages = () => { new api.ODWorker("opendiscord:ticket-message-components",1,async (instance,params,origin) => { const {guild,channel,user,ticket} = params //add components - if (generalConfig.data.system.enableTicketClaimButtons && !ticket.get("opendiscord:closed").value){ + if (generalConfig.data.ticketSystem.enableTicketClaimButtons && !ticket.get("opendiscord:closed").value){ //enable ticket claiming if (ticket.get("opendiscord:claimed").value){ instance.addComponent(await buttons.getSafe("opendiscord:unclaim-ticket").build("ticket-message",{guild,channel,user,ticket})) @@ -407,7 +407,7 @@ const ticketMessages = () => { instance.addComponent(await buttons.getSafe("opendiscord:claim-ticket").build("ticket-message",{guild,channel,user,ticket})) } } - if (generalConfig.data.system.enableTicketPinButtons && !ticket.get("opendiscord:closed").value){ + if (generalConfig.data.ticketSystem.enableTicketPinButtons && !ticket.get("opendiscord:closed").value){ //enable ticket pinning if (ticket.get("opendiscord:pinned").value){ instance.addComponent(await buttons.getSafe("opendiscord:unpin-ticket").build("ticket-message",{guild,channel,user,ticket})) @@ -415,7 +415,7 @@ const ticketMessages = () => { instance.addComponent(await buttons.getSafe("opendiscord:pin-ticket").build("ticket-message",{guild,channel,user,ticket})) } } - if (generalConfig.data.system.enableTicketCloseButtons){ + if (generalConfig.data.ticketSystem.enableTicketCloseButtons){ //enable ticket closing if (ticket.get("opendiscord:closed").value){ instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("ticket-message",{guild,channel,user,ticket})) @@ -424,7 +424,7 @@ const ticketMessages = () => { } } //enable ticket deletion - if (generalConfig.data.system.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("ticket-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("ticket-message",{guild,channel,user,ticket})) }), new api.ODWorker("opendiscord:ticket-message-disable-components",2,async (instance,params,origin) => { const {ticket} = params @@ -445,8 +445,8 @@ const ticketMessages = () => { new api.ODWorker("opendiscord:close-message",0,async (instance,params,origin) => { const {guild,channel,user,ticket,reason} = params instance.addEmbed(await embeds.getSafe("opendiscord:close-message").build(origin,{guild,channel,user,ticket,reason})) - if (generalConfig.data.system.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("close-message",{guild,channel,user,ticket})) - if (generalConfig.data.system.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("close-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("close-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("close-message",{guild,channel,user,ticket})) }) ) @@ -456,8 +456,8 @@ const ticketMessages = () => { new api.ODWorker("opendiscord:reopen-message",0,async (instance,params,origin) => { const {guild,channel,user,ticket,reason} = params instance.addEmbed(await embeds.getSafe("opendiscord:reopen-message").build(origin,{guild,channel,user,ticket,reason})) - if (generalConfig.data.system.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:close-ticket").build("reopen-message",{guild,channel,user,ticket})) - if (generalConfig.data.system.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("reopen-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:close-ticket").build("reopen-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("reopen-message",{guild,channel,user,ticket})) }) ) @@ -476,7 +476,7 @@ const ticketMessages = () => { new api.ODWorker("opendiscord:claim-message",0,async (instance,params,origin) => { const {guild,channel,user,ticket,reason} = params instance.addEmbed(await embeds.getSafe("opendiscord:claim-message").build(origin,{guild,channel,user,ticket,reason})) - if (generalConfig.data.system.enableTicketClaimButtons) instance.addComponent(await buttons.getSafe("opendiscord:unclaim-ticket").build("claim-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketClaimButtons) instance.addComponent(await buttons.getSafe("opendiscord:unclaim-ticket").build("claim-message",{guild,channel,user,ticket})) }) ) @@ -486,7 +486,7 @@ const ticketMessages = () => { new api.ODWorker("opendiscord:unclaim-message",0,async (instance,params,origin) => { const {guild,channel,user,ticket,reason} = params instance.addEmbed(await embeds.getSafe("opendiscord:unclaim-message").build(origin,{guild,channel,user,ticket,reason})) - if (generalConfig.data.system.enableTicketClaimButtons) instance.addComponent(await buttons.getSafe("opendiscord:claim-ticket").build("unclaim-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketClaimButtons) instance.addComponent(await buttons.getSafe("opendiscord:claim-ticket").build("unclaim-message",{guild,channel,user,ticket})) }) ) @@ -496,7 +496,7 @@ const ticketMessages = () => { new api.ODWorker("opendiscord:pin-message",0,async (instance,params,origin) => { const {guild,channel,user,ticket,reason} = params instance.addEmbed(await embeds.getSafe("opendiscord:pin-message").build(origin,{guild,channel,user,ticket,reason})) - if (generalConfig.data.system.enableTicketPinButtons) instance.addComponent(await buttons.getSafe("opendiscord:unpin-ticket").build("pin-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketPinButtons) instance.addComponent(await buttons.getSafe("opendiscord:unpin-ticket").build("pin-message",{guild,channel,user,ticket})) }) ) @@ -506,7 +506,7 @@ const ticketMessages = () => { new api.ODWorker("opendiscord:unpin-message",0,async (instance,params,origin) => { const {guild,channel,user,ticket,reason} = params instance.addEmbed(await embeds.getSafe("opendiscord:unpin-message").build(origin,{guild,channel,user,ticket,reason})) - if (generalConfig.data.system.enableTicketPinButtons) instance.addComponent(await buttons.getSafe("opendiscord:pin-ticket").build("unpin-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketPinButtons) instance.addComponent(await buttons.getSafe("opendiscord:pin-ticket").build("unpin-message",{guild,channel,user,ticket})) }) ) @@ -732,8 +732,8 @@ const autoMessages = () => { new api.ODWorker("opendiscord:autoclose-message",0,async (instance,params,origin) => { const {guild,channel,user,ticket} = params instance.addEmbed(await embeds.getSafe("opendiscord:autoclose-message").build(origin,{guild,channel,user,ticket})) - if (generalConfig.data.system.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("autoclose-message",{guild,channel,user,ticket})) - if (generalConfig.data.system.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("autoclose-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("autoclose-message",{guild,channel,user,ticket})) + if (generalConfig.data.ticketSystem.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("autoclose-message",{guild,channel,user,ticket})) }) ) diff --git a/src/commands/blacklist.ts b/src/commands/blacklist.ts index 7f445fc..10d0d18 100644 --- a/src/commands/blacklist.ts +++ b/src/commands/blacklist.ts @@ -14,7 +14,7 @@ export async function registerCommandResponders(){ const {guild,channel,user,member} = instance //check permissions - const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.blacklist,"support",user,member,channel,guild) + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.permissions.blacklist,"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(origin,{guild,channel,user,permissions:["support"]})) @@ -83,13 +83,13 @@ export async function registerCommandResponders(){ const reason = instance.options.getString("reason",false) //to logs - if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.blacklisting.logs){ + if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.blacklisting.logs){ const logChannel = opendiscord.posts.get("opendiscord:logs") if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-logs").build(origin,{guild,channel,user,mode:scope,data,reason})) } //to dm - if (generalConfig.data.system.messages.blacklisting.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:blacklist-dm").build(origin,{guild,channel,user,mode:scope,data,reason})) + if (generalConfig.data.logs.logMessages.blacklisting.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:blacklist-dm").build(origin,{guild,channel,user,mode:scope,data,reason})) }), new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => { const scope = instance.options.getSubCommand() diff --git a/src/commands/claim.ts b/src/commands/claim.ts index 38abf62..555e573 100644 --- a/src/commands/claim.ts +++ b/src/commands/claim.ts @@ -90,7 +90,7 @@ export async function registerButtonResponders(){ const originalMsgType = state.data.messageType //send verifybar - if (generalConfig.data.system.disableVerifyBars){ + if (generalConfig.data.ticketSystem.disableVerifyBars){ //verifybar disabled, directly run response await verifybar.activate(instance,"accept") diff --git a/src/commands/close.ts b/src/commands/close.ts index 9d60434..64f9595 100644 --- a/src/commands/close.ts +++ b/src/commands/close.ts @@ -95,7 +95,7 @@ export async function registerButtonResponders(){ const originalMsgType = state.data.messageType //send verifybar - if (generalConfig.data.system.disableVerifyBars){ + if (generalConfig.data.ticketSystem.disableVerifyBars){ //verifybar disabled, directly run response await verifybar.activate(instance,"accept") diff --git a/src/commands/delete.ts b/src/commands/delete.ts index 6b06348..8c153a8 100644 --- a/src/commands/delete.ts +++ b/src/commands/delete.ts @@ -36,7 +36,7 @@ export async function registerCommandResponders(){ //don't allow deleteWithoutTranscript to non-global-admins when enabled const withoutTranscript = instance.options.getBoolean("notranscript",false) ?? false - if (withoutTranscript && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){ + if (withoutTranscript && generalConfig.data.ticketSystem.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() @@ -93,7 +93,7 @@ export async function registerButtonResponders(){ const originalMsgType = state.data.messageType //send verifybar - if (generalConfig.data.system.disableVerifyBars){ + if (generalConfig.data.ticketSystem.disableVerifyBars){ //verifybar disabled, directly run response await verifybar.activate(instance,"accept") @@ -146,7 +146,7 @@ export async function registerVerifyBars(){ //don't allow deleteWithoutTranscript to non-global-admins when enabled const withoutTranscript = (params.selectedButtonId == "accept-without-transcript") - if (withoutTranscript && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){ + if (withoutTranscript && generalConfig.data.ticketSystem.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() diff --git a/src/commands/help.ts b/src/commands/help.ts index b852a3b..1ad49a2 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -19,7 +19,7 @@ export async function registerCommandResponders(){ //calculate slash/text mode for help menu let mode: "slash"|"text" - if (generalConfig.data.slashCommands && generalConfig.data.textCommands) mode = (generalConfig.data.system.preferSlashOverText) ? "slash" : "text" + if (generalConfig.data.slashCommands && generalConfig.data.textCommands) mode = (generalConfig.data.ticketSystem.preferSlashOverText) ? "slash" : "text" else if (!generalConfig.data.slashCommands) mode = "text" else mode = "slash" diff --git a/src/commands/pin.ts b/src/commands/pin.ts index 69def53..8ca9fc0 100644 --- a/src/commands/pin.ts +++ b/src/commands/pin.ts @@ -89,7 +89,7 @@ export async function registerButtonResponders(){ const originalMsgType = state.data.messageType //send verifybar - if (generalConfig.data.system.disableVerifyBars){ + if (generalConfig.data.ticketSystem.disableVerifyBars){ //verifybar disabled, directly run response await verifybar.activate(instance,"accept") diff --git a/src/commands/reopen.ts b/src/commands/reopen.ts index 94f7af1..2ba0772 100644 --- a/src/commands/reopen.ts +++ b/src/commands/reopen.ts @@ -89,7 +89,7 @@ export async function registerButtonResponders(){ const originalMsgType = state.data.messageType //send verifybar - if (generalConfig.data.system.disableVerifyBars){ + if (generalConfig.data.ticketSystem.disableVerifyBars){ //verifybar disabled, directly run response await verifybar.activate(instance,"accept") diff --git a/src/commands/role.ts b/src/commands/role.ts index 607125b..58dbc17 100644 --- a/src/commands/role.ts +++ b/src/commands/role.ts @@ -34,7 +34,7 @@ export async function registerButtonResponders(){ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel:instance.channel,user,error:"Unable to receive role update data from worker!",layout:"advanced"})) return cancel() } - if (generalConfig.data.system.replyOnReactionRole) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:reaction-role").build("panel-button",{guild,user,role:res.role,result:res.result})) + if (generalConfig.data.ticketSystem.replyOnReactionRole) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:reaction-role").build("panel-button",{guild,user,role:res.role,result:res.result})) }) ) } \ No newline at end of file diff --git a/src/commands/ticket.ts b/src/commands/ticket.ts index 719d523..92c1c86 100644 --- a/src/commands/ticket.ts +++ b/src/commands/ticket.ts @@ -105,7 +105,7 @@ export async function registerButtonResponders(){ if (!(await checkTicketCreationPerms(instance,"panel-button",guild,user,option))) return cancel() //CREATE TICKET - await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true) + await instance.defer((generalConfig.data.ticketSystem.replyOnTicketCreation) ? "reply" : "update",true) const res = await opendiscord.actions.get("opendiscord:create-ticket").run("panel-button",{guild,user,answers:[],option}) if (!res.channel || !res.ticket){ @@ -113,7 +113,7 @@ export async function registerButtonResponders(){ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel:instance.channel,user,error:"Unable to receive ticket or channel from callback! #1",layout:"advanced"})) return cancel() } - if (generalConfig.data.system.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build("panel-button",{guild,channel:res.channel,user,ticket:res.ticket})) + if (generalConfig.data.ticketSystem.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build("panel-button",{guild,channel:res.channel,user,ticket:res.ticket})) } }) ) @@ -147,7 +147,7 @@ export async function registerDropdownResponders(){ if (!(await checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option))) return cancel() //CREATE TICKET - await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true) + await instance.defer((generalConfig.data.ticketSystem.replyOnTicketCreation) ? "reply" : "update",true) const res = await opendiscord.actions.get("opendiscord:create-ticket").run("panel-dropdown",{guild,user,answers:[],option}) if (!res.channel || !res.ticket){ @@ -155,7 +155,7 @@ export async function registerDropdownResponders(){ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel:instance.channel,user,error:"Unable to receive ticket or channel from callback! #1",layout:"advanced"})) return cancel() } - if (generalConfig.data.system.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build("panel-dropdown",{guild,channel:res.channel,user,ticket:res.ticket})) + if (generalConfig.data.ticketSystem.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build("panel-dropdown",{guild,channel:res.channel,user,ticket:res.ticket})) } //update panel after dropdown usage (reset panel choice) @@ -214,7 +214,7 @@ export async function registerModalResponders(){ } }) - await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true) + await instance.defer((generalConfig.data.ticketSystem.replyOnTicketCreation) ? "reply" : "update",true) //CREATE TICKET const res = await opendiscord.actions.get("opendiscord:create-ticket").run(originalOrigin,{guild,user,answers,option}) @@ -223,7 +223,7 @@ export async function registerModalResponders(){ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"Unable to receive ticket or channel from callback! #2",layout:"advanced"})) return cancel() } - if (generalConfig.data.system.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build(originalOrigin,{guild,channel:res.channel,user,ticket:res.ticket})) + if (generalConfig.data.ticketSystem.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build(originalOrigin,{guild,channel:res.channel,user,ticket:res.ticket})) }) ]) } \ No newline at end of file diff --git a/src/commands/unclaim.ts b/src/commands/unclaim.ts index 13014b9..6250061 100644 --- a/src/commands/unclaim.ts +++ b/src/commands/unclaim.ts @@ -89,7 +89,7 @@ export async function registerButtonResponders(){ const originalMsgType = state.data.messageType //send verifybar - if (generalConfig.data.system.disableVerifyBars){ + if (generalConfig.data.ticketSystem.disableVerifyBars){ //verifybar disabled, directly run response await verifybar.activate(instance,"accept") diff --git a/src/commands/unpin.ts b/src/commands/unpin.ts index 30cd988..a49d772 100644 --- a/src/commands/unpin.ts +++ b/src/commands/unpin.ts @@ -89,7 +89,7 @@ export async function registerButtonResponders(){ const originalMsgType = state.data.messageType //send verifybar - if (generalConfig.data.system.disableVerifyBars){ + if (generalConfig.data.ticketSystem.disableVerifyBars){ //verifybar disabled, directly run response await verifybar.activate(instance,"accept") diff --git a/src/components/verifybarModifiers.ts b/src/components/verifybarModifiers.ts index 67c9115..60d35ed 100644 --- a/src/components/verifybarModifiers.ts +++ b/src/components/verifybarModifiers.ts @@ -42,7 +42,7 @@ export async function registerAllVerifyBarModifiers(){ //cancel, accept or close with reason await addVerifyButton(instance,params,"โŒ",true,api.ODVerifyButtonId.Cancel) await addVerifyButton(instance,params,"โœ…",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.close")) - if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") + if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") })) //REOPEN TICKET VERIFYBAR @@ -57,7 +57,7 @@ export async function registerAllVerifyBarModifiers(){ //cancel, accept or reopen with reason await addVerifyButton(instance,params,"โŒ",true,api.ODVerifyButtonId.Cancel) await addVerifyButton(instance,params,"โœ…",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.reopen")) - if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") + if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") })) //DELETE TICKET VERIFYBAR @@ -72,8 +72,8 @@ export async function registerAllVerifyBarModifiers(){ //cancel, accept or delete with reason or without transcript await addVerifyButton(instance,params,"โŒ",true,api.ODVerifyButtonId.Cancel) await addVerifyButton(instance,params,"โœ…",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.delete")) - if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") - if (generalConfig.data.system.enableDeleteWithoutTranscript) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithoutTranscript,lang.getTranslation("actions.buttons.withoutTranscript"),"red","๐Ÿ“„") + if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") + if (generalConfig.data.ticketSystem.enableDeleteWithoutTranscript) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithoutTranscript,lang.getTranslation("actions.buttons.withoutTranscript"),"red","๐Ÿ“„") })) //CLAIM TICKET VERIFYBAR @@ -88,7 +88,7 @@ export async function registerAllVerifyBarModifiers(){ //cancel, accept or claim with reason await addVerifyButton(instance,params,"โŒ",true,api.ODVerifyButtonId.Cancel) await addVerifyButton(instance,params,"โœ…",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.claim")) - if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") + if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") })) //UNCLAIM TICKET VERIFYBAR @@ -103,7 +103,7 @@ export async function registerAllVerifyBarModifiers(){ //cancel, accept or unclaim with reason await addVerifyButton(instance,params,"โŒ",true,api.ODVerifyButtonId.Cancel) await addVerifyButton(instance,params,"โœ…",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.unclaim")) - if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") + if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") })) //PIN TICKET VERIFYBAR @@ -118,7 +118,7 @@ export async function registerAllVerifyBarModifiers(){ //cancel, accept or pin with reason await addVerifyButton(instance,params,"โŒ",true,api.ODVerifyButtonId.Cancel) await addVerifyButton(instance,params,"โœ…",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.pin")) - if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") + if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") })) //UNPIN TICKET VERIFYBAR @@ -133,6 +133,6 @@ export async function registerAllVerifyBarModifiers(){ //cancel, accept or unpin with reason await addVerifyButton(instance,params,"โŒ",true,api.ODVerifyButtonId.Cancel) await addVerifyButton(instance,params,"โœ…",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.unpin")) - if (generalConfig.data.system.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") + if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"โœ…",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","โœ๏ธ") })) } \ No newline at end of file diff --git a/src/core/api/option.ts b/src/core/api/option.ts index fa70697..b5034a6 100644 --- a/src/core/api/option.ts +++ b/src/core/api/option.ts @@ -32,9 +32,6 @@ export interface ODTicketOptionIdMappings extends ODOptionIdConstraint { "opendiscord:channel-prefix":ODOptionData, "opendiscord:channel-suffix":ODOptionData<"user-name"|"user-nickname"|"user-id"|"random-number"|"random-hex"|"counter-dynamic"|"counter-fixed">, "opendiscord:channel-category":ODOptionData, - "opendiscord:channel-category-closed":ODOptionData, - "opendiscord:channel-category-backup":ODOptionData, - "opendiscord:channel-categories-claimed":ODOptionData<{user:string,category:string}[]>, "opendiscord:channel-topic":ODOptionData, "opendiscord:dm-message-enabled":ODOptionData, diff --git a/src/core/cli/quickSetup.ts b/src/core/cli/quickSetup.ts index af19d6d..6313977 100644 --- a/src/core/cli/quickSetup.ts +++ b/src/core/cli/quickSetup.ts @@ -31,7 +31,7 @@ interface ODQuickSetupVariables { globalUserLimit?:number|null, removeParticipantsOnClose?:boolean, ticketMessageLayout?:"embed"|"text"|null, - emojiStyle?:api.ODGeneralJsonConfig_System["emojiStyle"], + emojiStyle?:api.ODGeneralJsonConfig_TicketSystem["emojiStyle"], panelName?:string, panelDescription?:string, panelDropdown?:boolean, @@ -234,7 +234,7 @@ async function renderQuickSetupBotToken(backFn:() => api.ODPromiseVoid){ cli.renderHeader(headerOpts,"โฑ๏ธ Open Ticket Quick Setup: Bot Token") terminal.bold.blue(stepCount(2)+"Please insert the token of your discord bot.\n") - terminal.gray("This is used to configure the bot and is then stored securely in the './config/general.json' file.\n\n> ") + terminal.gray("This is used to configure the bot and is then stored securely in the './config/general.jsonc' file.\n\n> ") const answer = await terminal.inputField({ style:terminal.white, @@ -1203,11 +1203,7 @@ async function saveQuickSetupConfig(){ //GENERAL CONFIG const generalConfig = opendiscord.configs.get("opendiscord:general") const generalConfigData: api.ODGeneralJsonConfig_GeneralData = { - _INFO:{ - support:"https://otdocs.dj-dj.be", - discord:"https://discord.dj-dj.be", - version:"open-ticket-"+opendiscord.versions.get("opendiscord:version").toString() - }, + _CONFIG_VERSION:"open-ticket-"+opendiscord.versions.get("opendiscord:version").toString(), token:quickSetupStorage.client?.token ?? "", tokenFromENV:false, @@ -1222,8 +1218,29 @@ async function saveQuickSetupConfig(){ textCommands:quickSetupStorage.textCommands ?? false, status:quickSetupStorage.status ?? {enabled:false,mode:"online",type:"custom",text:"",state:""}, + logs:{ + enabled:(typeof quickSetupStorage.logChannel == "string"), + channel:quickSetupStorage.logChannel ?? "", + logMessages:{ + creation:{dm:true,logs:true}, + closing:{dm:true,logs:true}, + deleting:{dm:true,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:true,logs:true}, + blacklisting:{dm:true,logs:true}, + transferring:{dm:true,logs:true}, + topicChange:{dm:false,logs:true}, + priorityChange:{dm:false,logs:true}, + reactionRole:{dm:false,logs:true} + } + }, - system:{ + ticketSystem:{ preferSlashOverText:quickSetupStorage.slashCommands ?? false, sendErrorOnUnknownCommand:true, questionFieldsInCodeBlock:true, @@ -1234,10 +1251,11 @@ async function saveQuickSetupConfig(){ alwaysShowReason:false, emojiStyle:quickSetupStorage.emojiStyle ?? "before", pinEmoji:"๐Ÿ“Œ", + closeEmoji:"๐Ÿ”’", - replyOnTicketCreation:false, + replyOnTicketCreation:true, replyOnReactionRole:true, - askPriorityOnTicketCreation:false, + askPriorityOnTicketCreation:true, removeParticipantsOnClose:quickSetupStorage.removeParticipantsOnClose ?? false, disableAutocloseAfterReopen:true, autodeleteRequiresClosedTicket:true, @@ -1245,7 +1263,7 @@ async function saveQuickSetupConfig(){ allowCloseBeforeMessage:false, allowCloseBeforeAdminMessage:true, useTranslatedConfigChecker:true, - pinFirstTicketMessage:false, + pinFirstTicketMessage:true, enableTicketClaimButtons:true, enableTicketCloseButtons:true, @@ -1253,11 +1271,7 @@ async function saveQuickSetupConfig(){ enableTicketDeleteButtons:true, enableTicketActionWithReason:true, enableDeleteWithoutTranscript:true, - - logs:{ - enabled:(typeof quickSetupStorage.logChannel == "string"), - channel:quickSetupStorage.logChannel ?? "" - }, + enableCreateTicketForOtherUser:true, limits:{ enabled:(typeof quickSetupStorage.globalUserLimit == "number"), @@ -1276,49 +1290,41 @@ async function saveQuickSetupConfig(){ showCreator:false, showParticipants:false }, - - permissions:{ - help:"everyone", - panel:"admin", - ticket:"everyone", - close:"admin", - delete:"admin", - reopen:"admin", - 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", + + closedCategory:{ + enabled:false, + categoryId:"" }, - - messages:{ - creation:{dm:true,logs:true}, - closing:{dm:true,logs:true}, - deleting:{dm:true,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:true,logs:true}, - blacklisting:{dm:true,logs:true}, - transferring:{dm:true,logs:true}, - topicChange:{dm:false,logs:true}, - priorityChange:{dm:false,logs:true}, - reactionRole:{dm:false,logs:true} - } + backupCategory:{ + enabled:false, + categoryId:"" + }, + claimedCategories:[], + }, + permissions:{ + help:"everyone", + panel:"admin", + ticket:"everyone", + close:"admin", + delete:"admin", + reopen:"admin", + 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" } } generalConfig.data = generalConfigData @@ -1330,10 +1336,11 @@ async function saveQuickSetupConfig(){ { id:"example-question-1", name:"Example Question 1", + description:"This is a short text input question.", type:"short", - required:true, - placeholder:"Insert your short answer here!", + + placeholder:"Insert answer...", length:{ enabled:false, min:0, @@ -1343,15 +1350,69 @@ async function saveQuickSetupConfig(){ { id:"example-question-2", name:"Example Question 2", + description:"This is a paragraph text input question.", type:"paragraph", - required:false, - placeholder:"Insert your long answer here!", + + placeholder:"Insert answer...", length:{ enabled:false, min:0, max:1000 } + }, + { + id:"example-question-3", + name:"Example Question 3", + description:"This is a dropdown question.", + 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:"๐Ÿฅ"} + ] + }, + { + id:"example-question-4", + name:"Example Question 4", + description:"This is a radio select question.", + 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} + ] + }, + { + id:"example-question-5", + name:"Example Question 5", + description:"This is a checkbox select question.", + type:"checkbox-select", + required:true, + + limits:{ + 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} + ] + }, + { + id:"example-text-display", + type:"text-display", + textContents:"This is a text display. It isn't a question, but allows you to display a text, explaination or details." } ] questionsConfig.data = questionsConfigData @@ -1384,9 +1445,6 @@ async function saveQuickSetupConfig(){ prefix:ticket.channelPrefix, suffix:ticket.channelSuffix, category:quickSetupStorage.ticketCategory ?? "", - closedCategory:"", - backupCategory:"", - claimedCategory:[], topic:ticket.description }, @@ -1482,6 +1540,7 @@ async function saveQuickSetupConfig(){ }, settings:{ dropdownPlaceholder:"Open a ticket", + maximumButtonsPerRow:5, enableMaxTicketsWarningInText:(quickSetupStorage.panelLayout == "text" && (quickSetupStorage.panelMaxTicketsWarning ?? false)), enableMaxTicketsWarningInEmbed:(quickSetupStorage.panelLayout == "embed" && (quickSetupStorage.panelMaxTicketsWarning ?? false)), diff --git a/src/core/main.ts b/src/core/main.ts index fc5dceb..9ba8b41 100644 --- a/src/core/main.ts +++ b/src/core/main.ts @@ -58,7 +58,7 @@ export class ODOpenTicketMain extends api.ODMain { priorities: api.ODMappedPriorityManager constructor(){ - const version = api.ODVersion.fromString("opendiscord:version","v4.1.3") + const version = api.ODVersion.fromString("opendiscord:version","v4.2.0") const debugfile = new api.ODDebugFileManager("./","otdebug.txt",5000,version) const console = new api.ODConsoleManager(100,debugfile) const debug = new api.ODDebugger(console) @@ -108,7 +108,7 @@ export class ODOpenTicketMain extends api.ODMain { },"openticket") this.livestatus.useMain(this) - this.versions.add(api.ODVersion.fromString("opendiscord:version","v4.1.3")) + this.versions.add(api.ODVersion.fromString("opendiscord:version","v4.2.0")) this.versions.add(api.ODVersion.fromString("opendiscord:transcripts","v2.1.0")) //OPEN TICKET diff --git a/src/core/mappings/config.ts b/src/core/mappings/config.ts index 8e6c726..4f2114b 100644 --- a/src/core/mappings/config.ts +++ b/src/core/mappings/config.ts @@ -10,20 +10,20 @@ import { ODRoleUpdateMode } from "../api/role.js" * It's used to generate typescript declarations for this class. */ export interface ODConfigManagerIdMappings extends api.ODConfigManagerIdConstraint { - "opendiscord:general":ODGeneralJsonConfig, - "opendiscord:questions":ODQuestionsJsonConfig, - "opendiscord:options":ODOptionsJsonConfig, - "opendiscord:panels":ODPanelsJsonConfig, - "opendiscord:transcripts":ODTranscriptsJsonConfig + "opendiscord:general":ODGeneralJsonCommentsConfig, + "opendiscord:questions":ODQuestionsJsonCommentsConfig, + "opendiscord:options":ODOptionsJsonCommentsConfig, + "opendiscord:panels":ODPanelsJsonCommentsConfig, + "opendiscord:transcripts":ODTranscriptsJsonCommentsConfig } /////////////////////////////////////// // CONFIG STRUCTURES, VALUES & TYPES -// --> general.json +// --> general.jsonc /////////////////////////////////////// /**## ODGeneralJsonConfig_Status `interface` - * This interface is an object which has all properties for the status object in the `general.json` config! + * This interface is an object which has all properties for the status object in the `general.jsonc` config! */ export interface ODGeneralJsonConfig_Status { /**Is the status enabled? */ @@ -39,7 +39,7 @@ export interface ODGeneralJsonConfig_Status { } /**## ODGeneralJsonConfig_MessageSettings `interface` - * This interface is an object which has all properties for the "system"."messages".... object in the `general.json` config! + * This interface is an object which has all properties for the "system"."messages".... object in the `general.jsonc` config! */ export interface ODGeneralJsonConfig_MessageSettings { /**Enable sending DM logs to the ticket creator for this action. */ @@ -49,22 +49,10 @@ export interface ODGeneralJsonConfig_MessageSettings { } /**## ODGeneralJsonConfig_CmdPermissionSettingsType `type` - * This type is a collection of command permission settings for the "system"."permissions".... object in the `general.json` config! + * This type is a collection of command permission settings for the "system"."permissions".... object in the `general.jsonc` config! */ export type ODGeneralJsonConfig_CmdPermissionSettingsType = "admin"|"everyone"|"none"|string -/**## ODGeneralJsonConfig_Info `interface` - * This object contains a few URLs and metadata for the config. - */ -export interface ODGeneralJsonConfig_Info { - /**A link to the Open Ticket documentation. */ - support:string, - /**A link to the DJdj Development discord server. */ - discord:string, - /**The version of Open Ticket this config is compatible with. */ - version:string -} - /**## ODGeneralJsonConfig_SystemLogs `interface` * All settings related to the log channel. */ @@ -72,7 +60,9 @@ export interface ODGeneralJsonConfig_SystemLogs { /**Enable logging. Individual actions should still be added via the `"system"."messages"..."logs"` */ enabled:boolean, /**The channel to send logs to. */ - channel:string + channel:string, + /**Configure dm & log messages for all Open Ticket commands & actions. */ + logMessages:ODGeneralJsonConfig_LogMessages } /**## ODGeneralJsonConfig_SystemLimits `interface` @@ -137,12 +127,13 @@ export interface ODGeneralJsonConfig_SystemPermissions { transfer:ODGeneralJsonConfig_CmdPermissionSettingsType, topic:ODGeneralJsonConfig_CmdPermissionSettingsType, priority:ODGeneralJsonConfig_CmdPermissionSettingsType, + transcripts:ODGeneralJsonConfig_CmdPermissionSettingsType, } -/**## ODGeneralJsonConfig_SystemMessages `interface` +/**## ODGeneralJsonConfig_LogMessages `interface` * Configure dm & log messages for all Open Ticket commands & actions. */ -export interface ODGeneralJsonConfig_SystemMessages { +export interface ODGeneralJsonConfig_LogMessages { creation:ODGeneralJsonConfig_MessageSettings, closing:ODGeneralJsonConfig_MessageSettings, deleting:ODGeneralJsonConfig_MessageSettings, @@ -160,10 +151,10 @@ export interface ODGeneralJsonConfig_SystemMessages { reactionRole:ODGeneralJsonConfig_MessageSettings, } -/**## ODGeneralJsonConfig_System `interface` +/**## ODGeneralJsonConfig_TicketSystem `interface` * All settings related to the ticket system. */ -export interface ODGeneralJsonConfig_System { +export interface ODGeneralJsonConfig_TicketSystem { /**Prefer slash-commands over text-commands when displaying them in menu's and messages. */ preferSlashOverText:boolean, /**Reply with "unknown command" when the prefix is used without a valid command. */ @@ -184,6 +175,8 @@ export interface ODGeneralJsonConfig_System { emojiStyle:"before"|"after"|"double"|"disabled", /**The emoji used when pinning tickets. This is '๐Ÿ“Œ' by default. */ pinEmoji:string, + /**The emoji used when closing tickets. This is '๐Ÿ”’' by default. */ + closeEmoji:string, /**Reply with an ephemeral message when a ticket is created. */ replyOnTicketCreation:boolean, @@ -220,9 +213,8 @@ export interface ODGeneralJsonConfig_System { enableTicketActionWithReason:boolean, /**Enable/disable the delete without transcript feature (button & /delete command). */ enableDeleteWithoutTranscript:boolean, - - /**All settings related to the log channel. */ - logs:ODGeneralJsonConfig_SystemLogs, + /**Enable/disable creating tickets for other users with /ticket . (ADMIN ONLY) */ + enableCreateTicketForOtherUser:boolean, /**All settings related to global ticket limits. */ limits:ODGeneralJsonConfig_SystemLimits, @@ -230,19 +222,31 @@ export interface ODGeneralJsonConfig_System { /**All global channel topic settings. */ channelTopic:ODGeneralJsonConfig_SystemChannelTopic, - /**Configure permissions for all Open Ticket commands & actions. */ - permissions:ODGeneralJsonConfig_SystemPermissions, - - /**Configure dm & log messages for all Open Ticket commands & actions. */ - messages:ODGeneralJsonConfig_SystemMessages + /**Move closed tickets to this channel category. */ + closedCategory:{ + enabled:boolean + categoryId:string + }, + /**Create tickets in this channel category when the original category is full (max 50 channels). */ + backupCategory:{ + enabled:boolean + categoryId:string + }, + /**Move claimed tickets to the matching channel category of the user that claimed the ticket. */ + claimedCategories:{ + /**The user who claimed the ticket. */ + user:string, + /**The category to move the ticket to. */ + category:string + }[], } /**## ODGeneralJsonConfig_GeneralData `interface` - * All contents of the `general.json` config file. + * All contents of the `general.jsonc` config file. */ export interface ODGeneralJsonConfig_GeneralData { /**This object contains a few URLs and metadata for the config. */ - _INFO:ODGeneralJsonConfig_Info, + _CONFIG_VERSION:string, /**The token of the bot. (Empty when using `tokenFromENV`) */ token:string, @@ -267,18 +271,24 @@ export interface ODGeneralJsonConfig_GeneralData { /**All settings related to the status of the bot. */ status:ODGeneralJsonConfig_Status, - + /**All settings related to the ticket system. */ - system:ODGeneralJsonConfig_System + ticketSystem:ODGeneralJsonConfig_TicketSystem, + + /**Configure permissions for all Open Ticket commands & actions. */ + permissions:ODGeneralJsonConfig_SystemPermissions, + + /**All settings related to the log channel. */ + logs:ODGeneralJsonConfig_SystemLogs, } /////////////////////////////////////// // CONFIG STRUCTURES, VALUES & TYPES -// --> options.json +// --> options.jsonc /////////////////////////////////////// /**## ODOptionsJsonConfig_BaseOption `interface` - * This interface is an object which has all basic properties for options in the `options.json` config! + * The basic properties for options in the `options.jsonc` config! */ export interface ODOptionsJsonConfig_BaseOption { /**The id of this option. */ @@ -288,7 +298,7 @@ export interface ODOptionsJsonConfig_BaseOption { /**The description of this option. */ description:string, /**The type of this option. This type also determines the other option-specific variables. */ - type:"ticket"|"website"|"role", + type:"ticket"|"website"|"role"|"sub-panel", /**All settings related to the button for the 3 option types. */ button:{ /**The emoji of the button. (can also be empty) */ @@ -299,7 +309,7 @@ export interface ODOptionsJsonConfig_BaseOption { } /**## ODOptionsJsonConfig_OptionButtonSettings `interface` - * This interface is an object which has all button settings for ticket & reaction role options in the `options.json` config! + * The button settings for ticket, sub-panel & reaction role options in the `options.jsonc` config! */ export interface ODOptionsJsonConfig_OptionButtonSettings { /**The emoji of the button. (can also be empty) */ @@ -311,7 +321,7 @@ export interface ODOptionsJsonConfig_OptionButtonSettings { } /**## ODOptionsJsonConfig_TicketOptionEmbedSettings `interface` - * This interface is an object which has all message embed settings for ticket options in the `options.json` config! + * The message embed settings for ticket options in the `options.jsonc` config! */ export interface ODOptionsJsonConfig_TicketOptionEmbedSettings { /**Is this embed enabled? */ @@ -340,7 +350,7 @@ export interface ODOptionsJsonConfig_TicketOptionEmbedSettings { } /**## ODOptionsJsonConfig_TicketOptionPingSettings `interface` - * This interface is an object which has all message ping settings for ticket options in the `options.json` config! + * The message ping settings for ticket options in the `options.jsonc` config! */ export interface ODOptionsJsonConfig_TicketOptionPingSettings { /**Ping `@here`. */ @@ -361,23 +371,12 @@ export interface ODOptionsJsonConfig_TicketOptionChannelSettings { suffix:"user-name"|"user-nickname"|"user-id"|"random-number"|"random-hex"|"counter-dynamic"|"counter-fixed", /**An optional discord category id to create this ticket in. */ category:string, - /**An optional discord category id to move this ticket to when closed. */ - closedCategory:string, - /**An optional discord category id to create this ticket in when the primary one is full (max. 50 tickets). */ - backupCategory:string, - /**A list of discord category ids to move this ticket to when claimed by a specific user. */ - claimedCategory:{ - /**The user which claimed the ticket. */ - user:string, - /**The category to move the ticket to when claimed by this user. */ - category:string - }[], /**The channel topic shown at the top of the channel in discord. */ topic:string } /**## ODOptionsJsonConfig_TicketOption `interface` - * This interface is an object which has all ticket properties for options in the `options.json` config! + * All properties for ticket options in the `options.jsonc` config! */ export interface ODOptionsJsonConfig_TicketOption extends ODOptionsJsonConfig_BaseOption { type:"ticket", @@ -388,7 +387,7 @@ export interface ODOptionsJsonConfig_TicketOption extends ODOptionsJsonConfig_Ba readonlyAdmins:string[], /**When enabled, blacklisted users can still create this ticket type. (used for appeals, etc) */ allowCreationByBlacklistedUsers:boolean, - /**A list of valid question ids from the `questions.json` config. */ + /**A list of valid question ids from the `questions.jsonc` config. */ questions:string[], /**All settings related to the ticket channel itself. */ channel:ODOptionsJsonConfig_TicketOptionChannelSettings, @@ -460,7 +459,7 @@ export interface ODOptionsJsonConfig_TicketOption extends ODOptionsJsonConfig_Ba } /**## ODOptionsJsonConfig_WebsiteOption `interface` - * This interface is an object which has all website properties for options in the `options.json` config! + * All properties for website options in the `options.jsonc` config! */ export interface ODOptionsJsonConfig_WebsiteOption extends ODOptionsJsonConfig_BaseOption { type:"website", @@ -469,7 +468,7 @@ export interface ODOptionsJsonConfig_WebsiteOption extends ODOptionsJsonConfig_B } /**## ODOptionsJsonConfig_RoleOption `interface` - * This interface is an object which has all reaction role properties for options in the `options.json` config! + * All properties for reaction-role options in the `options.jsonc` config! */ export interface ODOptionsJsonConfig_RoleOption extends ODOptionsJsonConfig_BaseOption { type:"role", @@ -484,18 +483,28 @@ export interface ODOptionsJsonConfig_RoleOption extends ODOptionsJsonConfig_Base addOnMemberJoin:boolean } -/**## ODOptionsJsonConfig_OptionsData `type` - * All contents of the `options.json` config file. +/**## ODOptionsJsonConfig_SubPanelOption `interface` + * All properties for sub-panel options in the `options.jsonc` config! */ -export type ODOptionsJsonConfig_OptionsData = (ODOptionsJsonConfig_TicketOption|ODOptionsJsonConfig_WebsiteOption|ODOptionsJsonConfig_RoleOption)[] +export interface ODOptionsJsonConfig_SubPanelOption extends ODOptionsJsonConfig_BaseOption { + type:"sub-panel", + button:ODOptionsJsonConfig_OptionButtonSettings, + /**The panel ID of the sub-panel to show when the button is clicked. */ + subPanelId:string +} + +/**## ODOptionsJsonConfig_OptionsData `type` + * All contents of the `options.jsonc` config file. + */ +export type ODOptionsJsonConfig_OptionsData = (ODOptionsJsonConfig_TicketOption|ODOptionsJsonConfig_WebsiteOption|ODOptionsJsonConfig_RoleOption|ODOptionsJsonConfig_SubPanelOption)[] /////////////////////////////////////// // CONFIG STRUCTURES, VALUES & TYPES -// --> panels.json +// --> panels.jsonc /////////////////////////////////////// /**## ODPanelsJsonConfig_PanelEmbedSettings `interface` - * This interface is an object which has all message embed settings for panels in the `panels.json` config! + * This interface is an object which has all message embed settings for panels in the `panels.jsonc` config! */ export interface ODPanelsJsonConfig_PanelEmbedSettings { /**Is this embed enabled? */ @@ -535,6 +544,8 @@ export interface ODPanelsJsonConfig_PanelEmbedSettings { export interface ODPanelsJsonConfig_PanelSettings { /**The placeholder used in the dropdown when enabled. */ dropdownPlaceholder:string, + /**The maximum amount of option buttons before starting a new row. */ + maximumButtonsPerRow:number /**Enable a max tickets warning in the text contents. */ enableMaxTicketsWarningInText:boolean, @@ -554,7 +565,7 @@ export interface ODPanelsJsonConfig_PanelSettings { } /**## ODPanelsJsonConfig_Panel `interface` - * This interface is an object which has all properties for panels in the `panels.json` config! + * This interface is an object which has all properties for panels in the `panels.jsonc` config! */ export interface ODPanelsJsonConfig_Panel { /**The id of this panel. */ @@ -563,7 +574,7 @@ export interface ODPanelsJsonConfig_Panel { name:string, /**When enabled, the panel uses a dropdown instead of buttons. */ dropdown:boolean, - /**A list of valid options ids from the `options.json` config. */ + /**A list of valid options ids from the `options.jsonc` config. */ options:string[], /**The raw text contents of this panel. (empty for embed only) */ @@ -575,19 +586,19 @@ export interface ODPanelsJsonConfig_Panel { } /**## ODPanelsJsonConfig_PanelsData `type` - * All contents of the `panels.json` config file. + * All contents of the `panels.jsonc` config file. */ export type ODPanelsJsonConfig_PanelsData = ODPanelsJsonConfig_Panel[] /////////////////////////////////////// // CONFIG STRUCTURES, VALUES & TYPES -// --> questions.json +// --> questions.jsonc /////////////////////////////////////// -/**## ODQuestionsJsonConfig_QuestionLengthSettings `interface` +/**## ODQuestionsJsonConfig_TextLengthLimits `interface` * This interface is a collection of settings related to length validation in a question. */ -export interface ODQuestionsJsonConfig_QuestionLengthSettings { +export interface ODQuestionsJsonConfig_TextLengthLimits { /**Enable text length verification. */ enabled:boolean, /**The minimum text input length. */ @@ -596,48 +607,138 @@ export interface ODQuestionsJsonConfig_QuestionLengthSettings { max:number } +/**## ODQuestionsJsonConfig_CheckboxLimits `interface` + * The required amount of checkboxes validation in a question. + */ +export interface ODQuestionsJsonConfig_CheckboxLimits { + /**Enable checkbox limits. */ + enabled:boolean, + /**The minimum amount of selected checkboxes. */ + min:number, + /**The maximum amount of selected checkboxes. */ + max:number +} + +/**## ODQuestionsJsonConfig_DropdownChoice `interface` + * A dropdown choice used in `ODQuestionsJsonConfig_DropdownQuestion` + */ +export interface ODQuestionsJsonConfig_DropdownChoice { + /**The title of the choice. */ + title:string, + /**The optional description of the choice. (Leave empty for none) */ + description:string, + /**The optional emoji of the choice. (Leave empty for none) */ + emoji:string +} + +/**## ODQuestionsJsonConfig_RadioCheckboxChoice `interface` + * A radio/checkbox choice used in `ODQuestionsJsonConfig_RadioSelectQuestion` & `ODQuestionsJsonConfig_CheckboxSelectQuestion` + */ +export interface ODQuestionsJsonConfig_RadioCheckboxChoice { + /**The title of the choice. */ + title:string, + /**The optional description of the choice. (Leave empty for none) */ + description:string, + /**Is this choice selected by default? */ + selectedByDefault:boolean +} + /**## ODQuestionsJsonConfig_BaseQuestion `interface` - * This interface is an object which has all universal properties for questions in the `questions.json` config! + * This interface is an object which has all universal properties for questions in the `questions.jsonc` config! */ export interface ODQuestionsJsonConfig_BaseQuestion { /**The id of this question. */ id:string, /**The name of this question. */ name:string, + /**The description of this question. (Leave empty for none) */ + description:string, /**The type of this question. */ - type:"short"|"paragraph", + type:"short"|"paragraph"|"text-display"|"dropdown"|"radio-select"|"checkbox-select", /**Is this question required? */ required:boolean, } +/**## ODQuestionsJsonConfig_TextDisplayQuestion `interface` + * All properties for a text-display in the `questions.jsonc` config! + */ +export interface ODQuestionsJsonConfig_TextDisplayQuestion { + /**The id of this text-display. */ + id:string, + /**The type of this question. */ + type:"text-display", + /**The text contents to show in the modal. */ + textContents:string +} + /**## ODQuestionsJsonConfig_ShortQuestion `interface` - * This interface is an object which has all properties for short questions in the `questions.json` config! + * All properties for short questions in the `questions.jsonc` config! */ export interface ODQuestionsJsonConfig_ShortQuestion extends ODQuestionsJsonConfig_BaseQuestion { + type:"short", /**A placeholder for the question. */ placeholder:string, /**A collection of settings related to length validation in a question. */ - length:ODQuestionsJsonConfig_QuestionLengthSettings + length:ODQuestionsJsonConfig_TextLengthLimits } /**## ODQuestionsJsonConfig_ParagraphQuestion `interface` - * This interface is an object which has all properties for paragraph questions in the `questions.json` config! + * All properties for paragraph questions in the `questions.jsonc` config! */ export interface ODQuestionsJsonConfig_ParagraphQuestion extends ODQuestionsJsonConfig_BaseQuestion { + type:"paragraph", /**A placeholder for the question. */ placeholder:string, /**A collection of settings related to length validation in a question. */ - length:ODQuestionsJsonConfig_QuestionLengthSettings + length:ODQuestionsJsonConfig_TextLengthLimits +} + +/**## ODQuestionsJsonConfig_DropdownQuestion `interface` + * All properties for dropdown questions in the `questions.jsonc` config! + */ +export interface ODQuestionsJsonConfig_DropdownQuestion extends ODQuestionsJsonConfig_BaseQuestion { + type:"dropdown", + /**A placeholder for the dropdown. */ + placeholder:string, + /**A list of maximum 25 dropdown choices. */ + choices:ODQuestionsJsonConfig_DropdownChoice[] +} + +/**## ODQuestionsJsonConfig_RadioSelectQuestion `interface` + * All properties for radio select questions in the `questions.jsonc` config! + */ +export interface ODQuestionsJsonConfig_RadioSelectQuestion extends ODQuestionsJsonConfig_BaseQuestion { + type:"radio-select", + /**A list of minimum 2, maximum 10 radio choices. */ + choices:ODQuestionsJsonConfig_RadioCheckboxChoice[] +} + +/**## ODQuestionsJsonConfig_CheckboxSelectQuestion `interface` + * All properties for checkbox select questions in the `questions.jsonc` config! + */ +export interface ODQuestionsJsonConfig_CheckboxSelectQuestion extends ODQuestionsJsonConfig_BaseQuestion { + type:"checkbox-select", + /**Verify the checked amount of checkboxes with a minimum & maximum. */ + limits:ODQuestionsJsonConfig_CheckboxLimits + /**A list of minimum 1, maximum 10 checkbox choices. */ + choices:ODQuestionsJsonConfig_RadioCheckboxChoice[] } /**## ODQuestionsJsonConfig_QuestionsData `type` - * All contents of the `questions.json` config file. + * All contents of the `questions.jsonc` config file. */ -export type ODQuestionsJsonConfig_QuestionsData = (ODQuestionsJsonConfig_ShortQuestion|ODQuestionsJsonConfig_ParagraphQuestion)[] +export type ODQuestionsJsonConfig_QuestionsData = ( + ODQuestionsJsonConfig_ShortQuestion| + ODQuestionsJsonConfig_ParagraphQuestion| + ODQuestionsJsonConfig_TextDisplayQuestion| + ODQuestionsJsonConfig_DropdownQuestion| + ODQuestionsJsonConfig_RadioSelectQuestion| + ODQuestionsJsonConfig_CheckboxSelectQuestion +)[] /////////////////////////////////////// // CONFIG STRUCTURES, VALUES & TYPES -// --> transcripts.json +// --> transcripts.jsonc /////////////////////////////////////// /**## ODTranscriptsJsonConfig_TranscriptsTextLayout `interface` @@ -712,7 +813,7 @@ export interface ODTranscriptsJsonConfig_TranscriptsHtmlLayout { } /**## ODTranscriptsJsonConfig_TranscriptsData `interface` - * All contents of the `transcripts.json` config file. + * All contents of the `transcripts.jsonc` config file. */ export interface ODTranscriptsJsonConfig_TranscriptsData { /**All general settings related to transcripts. */ @@ -760,27 +861,27 @@ export interface ODTranscriptsJsonConfig_TranscriptsData { */ export class ODMappedConfigManager extends api.ODConfigManager {} -/**## ODGeneralJsonConfig `class - * A special class with types for the Open Ticket `config/general.json` config file +/**## ODGeneralJsonCommentsConfig `class + * A special class with types for the Open Ticket `config/general.jsonc` config file */ -export class ODGeneralJsonConfig extends api.ODJsonConfig {} +export class ODGeneralJsonCommentsConfig extends api.ODJsonCommentsConfig {} -/**## ODQuestionsJsonConfig `class - * A special class with types for the Open Ticket `config/questions.json` config file +/**## ODQuestionsJsonCommentsConfig `class + * A special class with types for the Open Ticket `config/questions.jsonc` config file */ -export class ODQuestionsJsonConfig extends api.ODJsonConfig {} +export class ODQuestionsJsonCommentsConfig extends api.ODJsonCommentsConfig {} -/**## ODOptionsJsonConfig `class - * A special class with types for the Open Ticket `config/options.json` config file +/**## ODOptionsJsonCommentsConfig `class + * A special class with types for the Open Ticket `config/options.jsonc` config file */ -export class ODOptionsJsonConfig extends api.ODJsonConfig {} +export class ODOptionsJsonCommentsConfig extends api.ODJsonCommentsConfig {} -/**## ODPanelsJsonConfig `class - * A special class with types for the Open Ticket `config/panels.json` config file +/**## ODPanelsJsonCommentsConfig `class + * A special class with types for the Open Ticket `config/panels.jsonc` config file */ -export class ODPanelsJsonConfig extends api.ODJsonConfig {} +export class ODPanelsJsonCommentsConfig extends api.ODJsonCommentsConfig {} -/**## ODTranscriptsJsonConfig `class - * A special class with types for the Open Ticket `config/transcripts.json` config file +/**## ODTranscriptsJsonCommentsConfig `class + * A special class with types for the Open Ticket `config/transcripts.jsonc` config file */ -export class ODTranscriptsJsonConfig extends api.ODJsonConfig {} \ No newline at end of file +export class ODTranscriptsJsonCommentsConfig extends api.ODJsonCommentsConfig {} \ No newline at end of file diff --git a/src/core/mappings/fuse.ts b/src/core/mappings/fuse.ts index 1b9255a..6e1ae00 100644 --- a/src/core/mappings/fuse.ts +++ b/src/core/mappings/fuse.ts @@ -6,21 +6,21 @@ import * as api from "@open-discord-bots/framework/api" export interface ODOpenTicketFuseList { /**Load the default Open Ticket ticket priority levels. */ priorityLoading:boolean, - /**Load the default Open Ticket questions (from `config/questions.json`) */ + /**Load the default Open Ticket questions (from `config/questions.jsonc`) */ questionLoading:boolean, - /**Load the default Open Ticket options (from `config/options.json`) */ + /**Load the default Open Ticket options (from `config/options.jsonc`) */ optionLoading:boolean, - /**Load the default Open Ticket panels (from `config/panels.json`) */ + /**Load the default Open Ticket panels (from `config/panels.jsonc`) */ panelLoading:boolean, /**Load the default Open Ticket tickets (from `database/tickets.json`) */ ticketLoading:boolean, - /**Load the default Open Ticket reaction roles (from `config/options.json`) */ + /**Load the default Open Ticket reaction roles (from `config/options.jsonc`) */ roleLoading:boolean, /**Load the default Open Ticket blacklist (from `database/users.json`) */ blacklistLoading:boolean, /**Load the default Open Ticket transcript compilers. */ transcriptCompilerLoading:boolean, - /**Load the default Open Ticket transcript history (from `database/transcripts.json`) */ + /**Load the default Open Ticket transcript history (from `database/transcripts.jsonc`) */ transcriptHistoryLoading:boolean, /**The interval in milliseconds that are between autoclose timeout checkers. */ autocloseCheckInterval:number, diff --git a/src/core/startup/manageMigration.ts b/src/core/startup/manageMigration.ts index ad4898c..5bd5eec 100644 --- a/src/core/startup/manageMigration.ts +++ b/src/core/startup/manageMigration.ts @@ -1,9 +1,24 @@ import {opendiscord, api, utilities} from "../../index.js" import fs from "fs" +import path from "path" + +/**Check if the no-migration flag is active. */ +function isMigrationAllowedFromFlag(){ + return (!process.argv.includes("--no-migration") && !process.argv.includes("-nm")) +} + +/**Read the global.json database raw to detect the last version of the bot. */ +function getRawLastVersion(){ + const isDevDatabase = process.argv.includes("--dev-database") || process.argv.includes("-dd") + const globalDatabaseLocation = path.join(process.cwd(),(isDevDatabase) ? "./devdatabase/global.json" : "./database/global.json") + const rawData: api.ODJsonDatabaseStructure = JSON.parse(fs.readFileSync(globalDatabaseLocation).toString()) + const lastVersion = rawData.find((d) => d.category == "opendiscord:last-version" && d.key == "opendiscord:version")?.value ?? null + return lastVersion as string|null +} /**Check if migration is required. Returns the last version used in the database. */ async function isMigrationRequired(): Promise { - const rawVersion = await opendiscord.databases.get("opendiscord:global").get("opendiscord:last-version","opendiscord:version") + const rawVersion = getRawLastVersion() if (!rawVersion) return false const version = api.ODVersion.fromString("opendiscord:last-version",rawVersion) if (opendiscord.versions.get("opendiscord:version").compare(version) == "higher"){ @@ -20,47 +35,6 @@ async function saveAllVersionsToDatabase(){ }) } -export async function loadVersionMigrationSystem(){ - //ENTER MIGRATION CONTEXT - await preloadMigrationContext() - - const lastVersion = await isMigrationRequired() - - //save last version to database (OR set to current version if no migration is required) - opendiscord.versions.add(lastVersion ? lastVersion : api.ODVersion.fromString("opendiscord:last-version",opendiscord.versions.get("opendiscord:version").toString())) - - if (lastVersion && !opendiscord.flags.get("opendiscord:no-migration").value){ - //MIGRATION IS REQUIRED - opendiscord.log("Detected old data!","info") - opendiscord.log("Starting closed API context...","debug") - await utilities.timer(600) - opendiscord.log("Migrating data to new version...","debug") - await loadAllVersionMigrations(lastVersion) - opendiscord.log("Stopping closed API context...","debug") - await utilities.timer(400) - opendiscord.log("All data is now up to date!","info") - await utilities.timer(200) - console.log("---------------------------------------------------------------------") - } - saveAllVersionsToDatabase() - - //DEFAULT FLAGS - if (opendiscord.flags.exists("opendiscord:no-plugins") && opendiscord.flags.get("opendiscord:no-plugins").value) opendiscord.sharedFuses.setFuse("pluginLoading",false) - if (opendiscord.flags.exists("opendiscord:soft-plugins") && opendiscord.flags.get("opendiscord:soft-plugins").value) opendiscord.sharedFuses.setFuse("softPluginLoading",true) - if (opendiscord.flags.exists("opendiscord:crash") && opendiscord.flags.get("opendiscord:crash").value) opendiscord.sharedFuses.setFuse("crashOnError",true) - if (opendiscord.flags.exists("opendiscord:force-slash-update") && opendiscord.flags.get("opendiscord:force-slash-update").value){ - opendiscord.sharedFuses.setFuse("forceSlashCommandRegistration",true) - opendiscord.sharedFuses.setFuse("forceContextMenuRegistration",true) - } - if (opendiscord.flags.exists("opendiscord:silent") && opendiscord.flags.get("opendiscord:silent").value) opendiscord.console.silent = true - - - //LEAVE MIGRATION CONTEXT - await unloadMigrationContext() - - return lastVersion -} - /**Initialize the migration context by loading the built-in flags, configs & databases. */ async function preloadMigrationContext(){ opendiscord.debug.debug("-- MIGRATION CONTEXT START --") @@ -73,6 +47,52 @@ async function preloadMigrationContext(){ opendiscord.debug.visible = true } +export async function loadVersionMigrationSystem(){ + const lastVersion = await isMigrationRequired() + + //save last version in version manager (OR set to current version if no migration is required) + opendiscord.versions.add(lastVersion ? lastVersion : api.ODVersion.fromString("opendiscord:last-version",opendiscord.versions.get("opendiscord:version").toString())) + + //MIGRATION IS REQUIRED + if (lastVersion && isMigrationAllowedFromFlag()){ + //BEFORE STARTUP MIGRATION + opendiscord.log("Detected old data!","info") + await loadBeforeStartupMigrations(lastVersion) + } + + //ENTER MIGRATION CONTEXT (must be separate for flags to work) + await preloadMigrationContext() + + if (lastVersion && isMigrationAllowedFromFlag()){ + //CONTEXT MIGRATION + opendiscord.log("Starting restricted API context...","debug") + await utilities.timer(600) + opendiscord.log("Migrating data to new version...","debug") + await loadContextMigrations(lastVersion) + opendiscord.log("Stopping restricted API context...","debug") + await utilities.timer(400) + opendiscord.log("All data is now up to date!","info") + await utilities.timer(200) + console.log("---------------------------------------------------------------------") + } + saveAllVersionsToDatabase() + + //SET FUSES & PROPERTIES OF SPECIAL FLAGS + if (opendiscord.flags.exists("opendiscord:no-plugins") && opendiscord.flags.get("opendiscord:no-plugins").value) opendiscord.sharedFuses.setFuse("pluginLoading",false) + if (opendiscord.flags.exists("opendiscord:soft-plugins") && opendiscord.flags.get("opendiscord:soft-plugins").value) opendiscord.sharedFuses.setFuse("softPluginLoading",true) + if (opendiscord.flags.exists("opendiscord:crash") && opendiscord.flags.get("opendiscord:crash").value) opendiscord.sharedFuses.setFuse("crashOnError",true) + if (opendiscord.flags.exists("opendiscord:force-slash-update") && opendiscord.flags.get("opendiscord:force-slash-update").value){ + opendiscord.sharedFuses.setFuse("forceSlashCommandRegistration",true) + opendiscord.sharedFuses.setFuse("forceContextMenuRegistration",true) + } + if (opendiscord.flags.exists("opendiscord:silent") && opendiscord.flags.get("opendiscord:silent").value) opendiscord.console.silent = true + + //LEAVE MIGRATION CONTEXT + await unloadMigrationContext() + + return lastVersion +} + /**Unload the migration context to start the bot normally. */ async function unloadMigrationContext(){ opendiscord.debug.visible = false @@ -98,8 +118,8 @@ function createMigrationBackup(){ else fs.cpSync("./database/","./.backup/database/",{force:true,recursive:true}) } -/**Execute all version migration functions which are handled in the restricted migration context. */ -async function loadAllVersionMigrations(lastVersion:api.ODVersion){ +/**Execute all version migration functions which are handled before any flags, configs or databases are loaded. */ +async function loadBeforeStartupMigrations(lastVersion:api.ODVersion){ const migrations = (await import("./migration.js")).migrations migrations.sort((a,b) => { const comparison = a.version.compare(b.version) @@ -114,10 +134,36 @@ async function loadAllVersionMigrations(lastVersion:api.ODVersion){ for (const migration of migrations){ if (migration.version.compare(lastVersion) == "higher"){ - const success = await migration.migrate() + const success = await migration.migrateBeforeStartup() if (success) opendiscord.log("Migrated data to "+migration.version.toString()+"!","debug",[ {key:"success",value:success ? "true" : "false"}, - {key:"afterInit",value:"false"} + {key:"type",value:"before-startup"} + ]) + else throw new api.ODSystemError("Migration Error: Unable to migrate database & config to the new version of the bot.") + } + } +} + +/**Execute all version migration functions which are handled in the restricted migration context. */ +async function loadContextMigrations(lastVersion:api.ODVersion){ + const migrations = (await import("./migration.js")).migrations + migrations.sort((a,b) => { + const comparison = a.version.compare(b.version) + if (comparison == "equal") return 0 + else if (comparison == "higher") return 1 + else return -1 + }) + if (migrations.length > 0){ + //create backup of config & database + createMigrationBackup() + } + + for (const migration of migrations){ + if (migration.version.compare(lastVersion) == "higher"){ + const success = await migration.migrateInContext() + if (success) opendiscord.log("Migrated data to "+migration.version.toString()+"!","debug",[ + {key:"success",value:success ? "true" : "false"}, + {key:"type",value:"restricted-context"} ]) else throw new api.ODSystemError("Migration Error: Unable to migrate database & config to the new version of the bot.") } @@ -125,7 +171,7 @@ async function loadAllVersionMigrations(lastVersion:api.ODVersion){ } /**Execute all version migration functions which are handled in the normal startup sequence. */ -export async function loadAllAfterInitVersionMigrations(lastVersion:api.ODVersion){ +export async function loadAfterStartupMigrations(lastVersion:api.ODVersion){ const migrations = (await import("./migration.js")).migrations migrations.sort((a,b) => { const comparison = a.version.compare(b.version) @@ -140,10 +186,10 @@ export async function loadAllAfterInitVersionMigrations(lastVersion:api.ODVersio for (const migration of migrations){ if (migration.version.compare(lastVersion) == "higher"){ - const success = await migration.migrateAfterInit() + const success = await migration.migrateAfterStartup() if (success) opendiscord.log("Migrated data to "+migration.version.toString()+"!","debug",[ {key:"success",value:success ? "true" : "false"}, - {key:"afterInit",value:"true"} + {key:"type",value:"after-startup"} ]) else throw new api.ODSystemError("Migration Error: Unable to migrate database & config to the new version of the bot.") } diff --git a/src/core/startup/migration.ts b/src/core/startup/migration.ts index e90d808..a62139f 100644 --- a/src/core/startup/migration.ts +++ b/src/core/startup/migration.ts @@ -1,147 +1,351 @@ import { opendiscord, api, utilities } from "../../index.js" +import fs from "fs" +import path from "path" export const migrations = [ //MIGRATE TO v4.0.0 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.0"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.0"),{}), //MIGRATE TO v4.0.1 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.1"),async () => {},async () => { - //AFTER INIT MIGRATION - - //add opendiscord:panel-message properties for all existing panels. - const globalDatabase = opendiscord.databases.get("opendiscord:global") - for (const panel of (await globalDatabase.getCategory("opendiscord:panel-update") ?? [])){ - globalDatabase.set("opendiscord:panel-message",panel.key,panel.value) + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.1"),{ + afterStartupMigrate:async () => { + //add opendiscord:panel-message properties for all existing panels. + const globalDatabase = opendiscord.databases.get("opendiscord:global") + for (const panel of (await globalDatabase.getCategory("opendiscord:panel-update") ?? [])){ + globalDatabase.set("opendiscord:panel-message",panel.key,panel.value) + } } }), //MIGRATE TO v4.0.2 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.2"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.2"),{}), //MIGRATE TO v4.0.3 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.3"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.3"),{}), //MIGRATE TO v4.0.4 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.4"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.4"),{}), //MIGRATE TO v4.0.5 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.5"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.5"),{}), //MIGRATE TO v4.0.6 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.6"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.6"),{}), //MIGRATE TO v4.0.7 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.7"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.0.7"),{}), //MIGRATE TO v4.1.0 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.0"),async () => {},async () => { - //AFTER INIT MIGRATION + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.0"),{ + afterStartupMigrate:async () => { + //migrate config + const generalConfig = opendiscord.configs.get("opendiscord:general") + const optionConfig = opendiscord.configs.get("opendiscord:options") - //migrate config - const generalConfig = opendiscord.configs.get("opendiscord:general") - const optionConfig = opendiscord.configs.get("opendiscord:options") + if (!generalConfig.data.status.state){ + //only migrate config when it hasn't been done manually by the user. - if (!generalConfig.data.status.state){ - //only migrate config when it hasn't been done manually by the user. + if (!generalConfig.data["_INFO"]) throw new api.ODSystemError("Couldn't find general.json '_INFO' category.") + generalConfig.data["_INFO"].version = "open-ticket-v4.1.0" - if (!generalConfig.data._INFO) throw new api.ODSystemError("Couldn't find general.json '_INFO' category.") - generalConfig.data._INFO.version = "open-ticket-v4.1.0" + if (!generalConfig.data.status) throw new api.ODSystemError("Couldn't find general.json 'status' category.") + generalConfig.data.status.mode = generalConfig.data.status["status"] ?? "online" + generalConfig.data.status.state = "" + delete generalConfig.data.status["status"] - if (!generalConfig.data.status) throw new api.ODSystemError("Couldn't find general.json 'status' category.") - generalConfig.data.status.mode = generalConfig.data.status["status"] ?? "online" - generalConfig.data.status.state = "" - delete generalConfig.data.status["status"] + if (!generalConfig.data["system"]) throw new api.ODSystemError("Couldn't find general.json 'system' category.") + generalConfig.data["system"].displayFieldsWithQuestions = false + generalConfig.data["system"].showGlobalAdminsInPanelRoles = false + generalConfig.data["system"].alwaysShowReason = false + generalConfig.data["system"].pinEmoji = "๐Ÿ“Œ" + generalConfig.data["system"].askPriorityOnTicketCreation = false + generalConfig.data["system"].disableAutocloseAfterReopen = true + generalConfig.data["system"].autodeleteRequiresClosedTicket = true + generalConfig.data["system"].adminOnlyDeleteWithoutTranscript = true + generalConfig.data["system"].allowCloseBeforeMessage = false + generalConfig.data["system"].allowCloseBeforeAdminMessage = true + generalConfig.data["system"].pinFirstTicketMessage = false - if (!generalConfig.data.system) throw new api.ODSystemError("Couldn't find general.json 'system' category.") - generalConfig.data.system.displayFieldsWithQuestions = false - generalConfig.data.system.showGlobalAdminsInPanelRoles = false - generalConfig.data.system.alwaysShowReason = false - generalConfig.data.system.pinEmoji = "๐Ÿ“Œ" - generalConfig.data.system.askPriorityOnTicketCreation = false - generalConfig.data.system.disableAutocloseAfterReopen = true - generalConfig.data.system.autodeleteRequiresClosedTicket = true - generalConfig.data.system.adminOnlyDeleteWithoutTranscript = true - generalConfig.data.system.allowCloseBeforeMessage = false - generalConfig.data.system.allowCloseBeforeAdminMessage = true - generalConfig.data.system.pinFirstTicketMessage = false - - generalConfig.data.system.channelTopic = { - showOptionName:true, - showOptionDescription:false, - showOptionTopic:true, - showPriority:false, - showClosed:true, - showClaimed:false, - showPinned:false, - showCreator:false, - showParticipants:false - } - - if (!generalConfig.data.system.permissions) throw new api.ODSystemError("Couldn't find general.json 'system.permissions' category.") - generalConfig.data.system.permissions.transfer = "admin" - generalConfig.data.system.permissions.topic = "admin" - generalConfig.data.system.permissions.priority = "admin" - - if (!generalConfig.data.system.messages) throw new api.ODSystemError("Couldn't find general.json 'system.messages' category.") - generalConfig.data.system.messages.transferring = {dm:false,logs:true} - generalConfig.data.system.messages.topicChange = {dm:false,logs:true} - generalConfig.data.system.messages.priorityChange = {dm:false,logs:true} - generalConfig.data.system.messages.reactionRole = generalConfig.data.system.messages["roleAdding"] ?? {dm:false,logs:true} - delete generalConfig.data.system.messages["roleAdding"] - delete generalConfig.data.system.messages["roleRemoving"] - - for (const option of optionConfig.data){ - if (option.type != "ticket") continue - option.channel.topic = option.channel["description"] ?? "" - delete option.channel["description"] - - option.slowMode = { - enabled:false, - slowModeSeconds:20 + generalConfig.data["system"].channelTopic = { + showOptionName:true, + showOptionDescription:false, + showOptionTopic:true, + showPriority:false, + showClosed:true, + showClaimed:false, + showPinned:false, + showCreator:false, + showParticipants:false } + + if (!generalConfig.data["system"].permissions) throw new api.ODSystemError("Couldn't find general.json 'system.permissions' category.") + generalConfig.data["system"].permissions.transfer = "admin" + generalConfig.data["system"].permissions.topic = "admin" + generalConfig.data["system"].permissions.priority = "admin" + + if (!generalConfig.data["system"].messages) throw new api.ODSystemError("Couldn't find general.json 'system.messages' category.") + generalConfig.data["system"].messages.transferring = {dm:false,logs:true} + generalConfig.data["system"].messages.topicChange = {dm:false,logs:true} + generalConfig.data["system"].messages.priorityChange = {dm:false,logs:true} + generalConfig.data["system"].messages.reactionRole = generalConfig.data["system"].messages["roleAdding"] ?? {dm:false,logs:true} + delete generalConfig.data["system"].messages["roleAdding"] + delete generalConfig.data["system"].messages["roleRemoving"] + + for (const option of optionConfig.data){ + if (option.type != "ticket") continue + option.channel.topic = option.channel["description"] ?? "" + delete option.channel["description"] + + option.slowMode = { + enabled:false, + slowModeSeconds:20 + } + } + + await generalConfig.save() + await optionConfig.save() } - await generalConfig.save() - await optionConfig.save() - } + //migrate database + const optionDatabase = opendiscord.databases.get("opendiscord:options") + const ticketDatabase = opendiscord.databases.get("opendiscord:tickets") - //migrate database - const optionDatabase = opendiscord.databases.get("opendiscord:options") - const ticketDatabase = opendiscord.databases.get("opendiscord:tickets") + for (const option of (await optionDatabase.getCategory("opendiscord:used-option") ?? [])){ + const optionData = option.value + + const topicData = optionData.data.find((d) => d.id == "opendiscord:channel-description") + if (topicData) topicData.id = "opendiscord:channel-topic" + if (!optionData.data.find((d) => d.id == "opendiscord:slowmode-enabled")) optionData.data.push({id:"opendiscord:slowmode-enabled",value:false}) + if (!optionData.data.find((d) => d.id == "opendiscord:slowmode-seconds")) optionData.data.push({id:"opendiscord:slowmode-seconds",value:20}) - for (const option of (await optionDatabase.getCategory("opendiscord:used-option") ?? [])){ - const optionData = option.value - - const topicData = optionData.data.find((d) => d.id == "opendiscord:channel-description") - if (topicData) topicData.id = "opendiscord:channel-topic" - if (!optionData.data.find((d) => d.id == "opendiscord:slowmode-enabled")) optionData.data.push({id:"opendiscord:slowmode-enabled",value:false}) - if (!optionData.data.find((d) => d.id == "opendiscord:slowmode-seconds")) optionData.data.push({id:"opendiscord:slowmode-seconds",value:20}) + optionDatabase.set("opendiscord:used-option",option.key,optionData) + } - optionDatabase.set("opendiscord:used-option",option.key,optionData) - } + for (const ticket of (await ticketDatabase.getCategory("opendiscord:ticket") ?? [])){ + const ticketData = ticket.value + + if (!ticketData.data.find((d) => d.id == "opendiscord:previous-creators")) ticketData.data.push({id:"opendiscord:previous-creators",value:[]}) + if (!ticketData.data.find((d) => d.id == "opendiscord:reopened")) ticketData.data.push({id:"opendiscord:reopened",value:false}) + if (!ticketData.data.find((d) => d.id == "opendiscord:reopened-by")) ticketData.data.push({id:"opendiscord:reopened-by",value:null}) + if (!ticketData.data.find((d) => d.id == "opendiscord:reopened-on")) ticketData.data.push({id:"opendiscord:reopened-on",value:null}) + if (!ticketData.data.find((d) => d.id == "opendiscord:priority")) ticketData.data.push({id:"opendiscord:priority",value:-1}) + if (!ticketData.data.find((d) => d.id == "opendiscord:topic")) ticketData.data.push({id:"opendiscord:topic",value:""}) + if (!ticketData.data.find((d) => d.id == "opendiscord:message-sent")) ticketData.data.push({id:"opendiscord:message-sent",value:true}) + if (!ticketData.data.find((d) => d.id == "opendiscord:admin-message-sent")) ticketData.data.push({id:"opendiscord:admin-message-sent",value:true}) - for (const ticket of (await ticketDatabase.getCategory("opendiscord:ticket") ?? [])){ - const ticketData = ticket.value - - if (!ticketData.data.find((d) => d.id == "opendiscord:previous-creators")) ticketData.data.push({id:"opendiscord:previous-creators",value:[]}) - if (!ticketData.data.find((d) => d.id == "opendiscord:reopened")) ticketData.data.push({id:"opendiscord:reopened",value:false}) - if (!ticketData.data.find((d) => d.id == "opendiscord:reopened-by")) ticketData.data.push({id:"opendiscord:reopened-by",value:null}) - if (!ticketData.data.find((d) => d.id == "opendiscord:reopened-on")) ticketData.data.push({id:"opendiscord:reopened-on",value:null}) - if (!ticketData.data.find((d) => d.id == "opendiscord:priority")) ticketData.data.push({id:"opendiscord:priority",value:-1}) - if (!ticketData.data.find((d) => d.id == "opendiscord:topic")) ticketData.data.push({id:"opendiscord:topic",value:""}) - if (!ticketData.data.find((d) => d.id == "opendiscord:message-sent")) ticketData.data.push({id:"opendiscord:message-sent",value:true}) - if (!ticketData.data.find((d) => d.id == "opendiscord:admin-message-sent")) ticketData.data.push({id:"opendiscord:admin-message-sent",value:true}) - - ticketDatabase.set("opendiscord:ticket",ticket.key,ticketData) + ticketDatabase.set("opendiscord:ticket",ticket.key,ticketData) + } } }), //MIGRATE TO v4.1.1 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.1"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.1"),{}), //MIGRATE TO v4.1.2 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.2"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.2"),{}), //MIGRATE TO v4.1.3 - new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.3"),async () => {},async () => {}), + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.3"),{}), + + //MIGRATE TO v4.2.0 + new api.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.2.0"),{ + beforeStartupMigrate:async () => { + const isDevconfig = (process.argv.includes("--dev-config") || process.argv.includes("-dc")) + + //transfer config files to .jsonc + const configDir = path.join(process.cwd(),(isDevconfig) ? "./devconfig/" : "./config/") + for (const file of fs.readdirSync(configDir).filter((f) => f.endsWith(".json"))){ + try{ + fs.copyFileSync(path.join(configDir,file),path.join(configDir,file.replace(".json",".jsonc"))) + fs.rmSync(path.join(configDir,file)) + }catch(err){ + process.emit("uncaughtException",err) + } + } + }, + afterStartupMigrate:async () => { + //migrate config + const generalConfig = opendiscord.configs.get("opendiscord:general") + const questionConfig = opendiscord.configs.get("opendiscord:questions") + const optionConfig = opendiscord.configs.get("opendiscord:options") + const panelConfig = opendiscord.configs.get("opendiscord:panels") + const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts") + + if (!generalConfig.data.ticketSystem){ + //only migrate config when it hasn't been done manually by the user. + + if (!generalConfig.data["_INFO"]) throw new api.ODSystemError("Couldn't find general.jsonc '_INFO' category.") + delete generalConfig.data["_INFO"] + generalConfig.data._CONFIG_VERSION = "open-ticket-v4.2.0" + + if (!generalConfig.data["system"]) throw new api.ODSystemError("Couldn't find general.jsonc 'system' category.") + generalConfig.data.ticketSystem = generalConfig.data["system"] + generalConfig.data.ticketSystem.closeEmoji = "๐Ÿ”’" + generalConfig.data.ticketSystem.askPriorityOnTicketCreation = true + generalConfig.data.ticketSystem.enableCreateTicketForOtherUser = true + delete generalConfig.data["system"] + generalConfig.data.logs = generalConfig.data.ticketSystem["logs"] + delete generalConfig.data.ticketSystem["logs"] + generalConfig.data.logs.logMessages = generalConfig.data.ticketSystem["messages"] + delete generalConfig.data.ticketSystem["messages"] + generalConfig.data.permissions = generalConfig.data.ticketSystem["permissions"] + delete generalConfig.data.ticketSystem["permissions"] + generalConfig.data.permissions.transcripts = "admin" + + //closed category + const closedCategory = {enabled:false,categoryId:"DISCORD_CATEGORY_ID"} + for (const option of optionConfig.data){ + if (option.type != "ticket") continue + if (option.channel["closedCategory"] && /^\d+$/.test(option.channel["closedCategory"])){ + closedCategory.enabled = true + closedCategory.categoryId = option.channel["closedCategory"] + } + } + generalConfig.data.ticketSystem.closedCategory = closedCategory + + //backup category + const backupCategory = {enabled:false,categoryId:"DISCORD_CATEGORY_ID"} + for (const option of optionConfig.data){ + if (option.type != "ticket") continue + if (option.channel["backupCategory"] && /^\d+$/.test(option.channel["backupCategory"])){ + backupCategory.enabled = true + backupCategory.categoryId = option.channel["backupCategory"] + } + } + generalConfig.data.ticketSystem.backupCategory = backupCategory + + //claimed categories + const claimedCategories: {user:string,category:string}[] = [] + for (const option of optionConfig.data){ + if (option.type != "ticket" || !Array.isArray(option.channel["claimedCategory"])) continue + for (const {user,category} of option.channel["claimedCategory"]){ + if (typeof user == "string" && typeof category == "string" && /^\d+$/.test(user) && /^\d+$/.test(category) && !claimedCategories.find((c) => c.user == user)){ + claimedCategories.push({user,category}) + } + } + } + generalConfig.data.ticketSystem.claimedCategories = claimedCategories + + + //delete properties from options.jsonc + for (const option of optionConfig.data){ + if (option.type != "ticket") continue + delete option.channel["closedCategory"] + delete option.channel["backupCategory"] + delete option.channel["claimedCategory"] + } + + //update panels config: + for (const panel of panelConfig.data){ + panel.settings.maximumButtonsPerRow = 5 + } + + //update questions config: + for (const question of questionConfig.data){ + if (question.type !== "paragraph" && question.type !== "short") continue + question.description = "" + } + + //add new sub-panel option example (for users to try) + optionConfig.data.push({ + id:"example-sub-panel", + name:"Example Sub-Panel", + description:"This is an example of how to implement a sub-panel in Open Ticket.", + type:"sub-panel", + + button:{ + color:"gray", + label:"Sub-Panel Example", + emoji:"๐Ÿ“‹" + }, + subPanelId:panelConfig.data[0]?.id ?? "example-panel" + }) + + //add new question examples (for users to try) + questionConfig.data.push( + { + id:"example-dropdown-question", + name:"Example Dropdown Question", + description:"This is a dropdown question.", + 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:"๐Ÿฅ"} + ] + }, + { + id:"example-radio-question", + name:"Example Radio Question", + description:"This is a radio select question.", + 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} + ] + }, + { + id:"example-checkbox-question", + name:"Example Checkbox Question", + description:"This is a checkbox select question.", + type:"checkbox-select", + required:true, + + limits:{ + 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} + ] + }, + { + id:"example-text-display-question", + type:"text-display", + textContents:"This is a text display. It isn't a question, but allows you to display a text, explaination or details." + } + ) + + await generalConfig.save() + await questionConfig.save() + await optionConfig.save() + await panelConfig.save() + await transcriptConfig.save() + } + + //migrate database + const optionDatabase = opendiscord.databases.get("opendiscord:options") + const ticketDatabase = opendiscord.databases.get("opendiscord:tickets") + + for (const option of (await optionDatabase.getCategory("opendiscord:used-option") ?? [])){ + const optionData = option.value + optionData.data = optionData.data.filter((data) => ( + data.id !== "opendiscord:channel-category-closed" && + data.id !== "pendiscord:channel-category-backup" && + data.id !== "opendiscord:channel-categories-claimed" + )) + + optionDatabase.set("opendiscord:used-option",option.key,optionData) + } + + for (const ticket of (await ticketDatabase.getCategory("opendiscord:ticket") ?? [])){ + const ticketData = ticket.value + if (!ticketData.data.find((d) => d.id == "opendiscord:channel-renamed")) ticketData.data.push({id:"opendiscord:channel-renamed",value:null}) + + ticketDatabase.set("opendiscord:ticket",ticket.key,ticketData) + } + } + }), ] \ No newline at end of file diff --git a/src/data/framework/checkerLoader.ts b/src/data/framework/checkerLoader.ts index 2a26a05..182f814 100644 --- a/src/data/framework/checkerLoader.ts +++ b/src/data/framework/checkerLoader.ts @@ -17,7 +17,7 @@ export async function loadAllConfigCheckerFunctions(){ } export async function loadAllConfigCheckerTranslations(){ - if ((generalConfig && generalConfig.data.system && generalConfig.data.system.useTranslatedConfigChecker) ? generalConfig.data.system.useTranslatedConfigChecker : false){ + if ((generalConfig && generalConfig.data.ticketSystem && generalConfig.data.ticketSystem.useTranslatedConfigChecker) ? generalConfig.data.ticketSystem.useTranslatedConfigChecker : false){ registerDefaultCheckerSystemTranslations(opendiscord.checkers.translation,opendiscord.languages) //translate checker system text registerDefaultCheckerMessageTranslations(opendiscord.checkers.translation,opendiscord.languages) //translate checker messages registerDefaultCheckerCustomTranslations(opendiscord.checkers.translation,opendiscord.languages) //translate custom checker messages @@ -25,7 +25,7 @@ export async function loadAllConfigCheckerTranslations(){ } //GLOBAL FUNCTIONS -export const registerDefaultCheckerSystemTranslations = (tm:api.ODMappedCheckerTranslationRegister,lm:api.ODMappedLanguageManager) => { +export function registerDefaultCheckerSystemTranslations(tm:api.ODMappedCheckerTranslationRegister,lm:api.ODMappedLanguageManager){ //SYSTEM tm.quickTranslate(lm,"checker.system.headerOpenTicket","other","opendiscord:header-projectname") //OPEN TICKET tm.quickTranslate(lm,"checker.system.typeError","other","opendiscord:type-error") // [ERROR] (ignore) @@ -42,7 +42,7 @@ export const registerDefaultCheckerSystemTranslations = (tm:api.ODMappedCheckerT tm.quickTranslate(lm,"checker.system.dataMessages","other","opendiscord:data-message") // message } -export const registerDefaultCheckerMessageTranslations = (tm:api.ODMappedCheckerTranslationRegister,lm:api.ODMappedLanguageManager) => { +export function registerDefaultCheckerMessageTranslations(tm:api.ODMappedCheckerTranslationRegister,lm:api.ODMappedLanguageManager){ //STRUCTURES tm.quickTranslate(lm,"checker.messages.invalidType","message","opendiscord:invalid-type") // This property needs to be the type: {0}! tm.quickTranslate(lm,"checker.messages.propertyMissing","message","opendiscord:property-missing") // The property {0} is missing from this object! @@ -117,7 +117,7 @@ export const registerDefaultCheckerMessageTranslations = (tm:api.ODMappedChecker tm.quickTranslate(lm,"checker.messages.idNonExistent","message","opendiscord:id-non-existent") // The id {0} doesn't exist! } -export const registerDefaultCheckerCustomTranslations = (tm:api.ODMappedCheckerTranslationRegister,lm:api.ODMappedLanguageManager) => { +export function registerDefaultCheckerCustomTranslations(tm:api.ODMappedCheckerTranslationRegister,lm:api.ODMappedLanguageManager){ //CUSTOM tm.quickTranslate(lm,"checker.messages.invalidLanguage","message","opendiscord:invalid-language") // This is an invalid language! tm.quickTranslate(lm,"checker.messages.invalidButton","message","opendiscord:invalid-button") // This button needs to have at least an {0} or {1}! @@ -128,13 +128,30 @@ export const registerDefaultCheckerCustomTranslations = (tm:api.ODMappedCheckerT } //UTILITY FUNCTIONS -const createMsgStructure = (id:api.ODValidId,displayName:string) => { +/**Get the panel ids from `panels.jsonc` before it has been checked by the config checker. */ +function getUnsafePanelIds(): string[] { + const panelsConfig = opendiscord.configs.get("opendiscord:panels") + if (!Array.isArray(panelsConfig.data)) return [] + + const panelIds: string[] = [] + for (const unsafePanel of panelsConfig.data){ + if (unsafePanel["id"]) panelIds.push(unsafePanel["id"]) + } + return panelIds +} + +function createMsgStructure(id:api.ODValidId,displayName:string){ return new api.ODCheckerObjectStructure(id,{children:[ {key:"dm",checker:new api.ODCheckerBooleanStructure("opendiscord:msg-dm",{cliInitDefaultValue:false,cliDisplayName:"DM Enabled",cliDisplayDescription:"Will this action be sent in DM to the creator of the ticket?"})}, {key:"logs",checker:new api.ODCheckerBooleanStructure("opendiscord:msg-logs",{cliInitDefaultValue:true,cliDisplayName:"Logs Enabled",cliDisplayDescription:"Will this action be sent in the Discord log channel?"})}, ],cliDisplayName:displayName,cliDisplayDescription:"Configure which places this action gets logged/sent to."}) } -const createTicketEmbedStructure = (id:api.ODValidId) => { + +function createPermissionStructure(id:api.ODValidId,displayName:string){ + return new api.ODCheckerCustomStructure_DiscordId(id,"role",false,["admin","everyone","none"],{cliDisplayName:displayName,cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."}) +} + +function createTicketEmbedStructure(id:api.ODValidId){ return new api.ODCheckerEnabledObjectStructure(id,{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure(id,{children:[ {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:ticket-embed-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable the embed of this message."})}, {key:"title",checker:new api.ODCheckerStringStructure("opendiscord:ticket-embed-text",{maxLength:256,cliDisplayName:"Title",cliDisplayDescription:"The title of this embed."})}, @@ -151,14 +168,16 @@ const createTicketEmbedStructure = (id:api.ODValidId) => { {key:"timestamp",checker:new api.ODCheckerBooleanStructure("opendiscord:ticket-embed-timestamp",{cliDisplayName:"Timestamp",cliDisplayDescription:"Add a timestamp to the embed."})} ],cliDisplayName:"Message Embed",cliDisplayDescription:"Configure the embed of this message."}),cliInitDefaultValue:{enabled:false,title:"",description:"",customColor:"",image:"",thumbnail:"",fields:[],timestamp:false},cliDisplayName:"Message Embed",cliDisplayDescription:"Configure the embed of this message."}) } -const createTicketPingStructure = (id:api.ODValidId) => { + +function createTicketPingStructure(id:api.ODValidId){ return new api.ODCheckerObjectStructure(id,{children:[ {key:"@here",checker:new api.ODCheckerBooleanStructure("opendiscord:ticket-ping-here",{cliDisplayName:"@here Ping",cliDisplayDescription:"Enable/disable an '@here' ping."})}, {key:"@everyone",checker:new api.ODCheckerBooleanStructure("opendiscord:ticket-ping-everyone",{cliDisplayName:"@everyone Ping",cliDisplayDescription:"Enable/disable an '@everyone' ping."})}, {key:"custom",checker:new api.ODCheckerCustomStructure_DiscordIdArray("opendiscord:ticket-ping-custom","role",[],{allowDoubles:false,cliDisplayPropertyName:"custom role id",cliDisplayName:"Custom Role Ping",cliDisplayDescription:"Choose your own roles to ping in this message."},{cliDisplayName:"Custom Role",cliDisplayDescription:"The discord role ID of a custom mention/ping."})}, ],cliInitDefaultValue:{"@here":true,"@everyone":false,custom:[],cliDisplayName:"Message Pings",cliDisplayDescription:"Configure the pings/mentions of this message."}}) } -const createPanelEmbedStructure = (id:api.ODValidId) => { + +function createPanelEmbedStructure(id:api.ODValidId){ return new api.ODCheckerEnabledObjectStructure(id,{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure(id,{children:[ {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:panel-embed-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable the embed of this panel."})}, {key:"title",checker:new api.ODCheckerStringStructure("opendiscord:panel-embed-text",{maxLength:256,cliDisplayName:"Title",cliDisplayDescription:"The title of this embed."})}, @@ -188,23 +207,19 @@ function loadFromEnv(){ //STRUCTURES export const defaultGeneralStructure = new api.ODCheckerObjectStructure("opendiscord:general",{children:[ //INFO - {key:"_INFO",cliHideInEditMode:true,checker:new api.ODCheckerObjectStructure("opendiscord:info",{children:[ - {key:"support",checker:new api.ODCheckerStringStructure("opendiscord:info-support",{choices:["https://otdocs.dj-dj.be"]})}, - {key:"discord",checker:new api.ODCheckerStringStructure("opendiscord:info-discord",{choices:["https://discord.dj-dj.be"]})}, - {key:"version",checker:new api.ODCheckerStringStructure("opendiscord:info-version",{custom(checker,value,locationTrace,locationId,locationDocs) { - const lt = checker.locationTraceDeref(locationTrace) - - if (typeof value != "string") return false - else if (value != "open-ticket-"+opendiscord.versions.get("opendiscord:version").toString()){ - checker.createMessage("opendiscord:invalid-version","warning","The version specified in your config does not match! Make sure you have updated the config to the latest version!",lt,null,[],locationId,locationDocs) - return false - }else return true - },})}, - ]})}, + {key:"_CONFIG_VERSION",cliHideInEditMode:true,checker:new api.ODCheckerStringStructure("opendiscord:config-version",{custom(checker,value,locationTrace,locationId,locationDocs) { + const lt = checker.locationTraceDeref(locationTrace) + + if (typeof value != "string") return false + else if (value != "open-ticket-"+opendiscord.versions.get("opendiscord:version").toString()){ + checker.createMessage("opendiscord:invalid-version","warning","The version specified in your config does not match! Make sure you have updated the config to the latest version!",lt,null,[],locationId,locationDocs) + return false + }else return true + },})}, //BASIC {key:"token",checker:(loadFromEnv()) ? new api.ODCheckerStringStructure("opendiscord:token-disabled",{cliDisplayName:"Token",cliDisplayDescription:"The token of your discord bot."}) : new api.ODCheckerCustomStructure_DiscordToken("opendiscord:token",{cliDisplayName:"Token",cliDisplayDescription:"The token of your discord bot."})}, - {key:"tokenFromENV",checker:new api.ODCheckerBooleanStructure("opendiscord:token-env",{cliDisplayName:"Token From ENV",cliDisplayDescription:"Use the token from the .env file instead of general.json."})}, + {key:"tokenFromENV",checker:new api.ODCheckerBooleanStructure("opendiscord:token-env",{cliDisplayName:"Token From ENV",cliDisplayDescription:"Use the token from the .env file instead of general.jsonc."})}, {key:"mainColor",checker:new api.ODCheckerCustomStructure_HexColor("opendiscord:main-color",true,false,{cliDisplayName:"Main Color",cliDisplayDescription:"The main color of your bot, used in almost all embeds."})}, {key:"language",checker:new api.ODCheckerStringStructure("opendiscord:language",{ custom:(checker,value,locationTrace,locationId,locationDocs) => { @@ -230,6 +245,7 @@ export const defaultGeneralStructure = new api.ODCheckerObjectStructure("opendis {key:"status",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:status",{ property:"enabled", enabledValue:true, + ignoreCheckIfDisabled:true, checker:new api.ODCheckerObjectStructure("opendiscord:status",{children:[ {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:status-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable the status. When disabled, the bot will be online without any status."})}, {key:"type",checker:new api.ODCheckerStringStructure("opendiscord:status-type",{choices:["listening","watching","playing","custom"],cliDisplayName:"Type",cliDisplayDescription:"The type of status: Listening, Watching, Playing or Custom."})}, @@ -241,8 +257,8 @@ export const defaultGeneralStructure = new api.ODCheckerObjectStructure("opendis cliDisplayDescription:"Manage the status of the bot." })}, - //SYSTEM - {key:"system",checker:new api.ODCheckerObjectStructure("opendiscord:system",{children:[ + //TICKET SYSTEM + {key:"ticketSystem",checker:new api.ODCheckerObjectStructure("opendiscord:ticket-system",{children:[ {key:"preferSlashOverText",checker:new api.ODCheckerBooleanStructure("opendiscord:prefer-slash-over-text",{cliDisplayName:"Prefer Slash Over Text",cliDisplayDescription:"Prefer displaying slash commands over text commands in help menus."})}, {key:"sendErrorOnUnknownCommand",checker:new api.ODCheckerBooleanStructure("opendiscord:send-error-on-unknown-command",{cliDisplayName:"Send Error On Unknown Command",cliDisplayDescription:"Send an error when using the text-command prefix without a valid command."})}, {key:"questionFieldsInCodeBlock",checker:new api.ODCheckerBooleanStructure("opendiscord:question-fields-in-code-block",{cliDisplayName:"Questions Fields In Code Blocks",cliDisplayDescription:"Display question fields in code blocks instead of plain text."})}, @@ -252,7 +268,8 @@ export const defaultGeneralStructure = new api.ODCheckerObjectStructure("opendis {key:"useRedErrorEmbeds",checker:new api.ODCheckerBooleanStructure("opendiscord:use-red-error-embeds",{cliDisplayName:"Use Red Error Embeds",cliDisplayDescription:"Display all error messages with a red border instead of the default color of the bot."})}, {key:"alwaysShowReason",checker:new api.ODCheckerBooleanStructure("opendiscord:always-show-reason",{cliDisplayName:"Always Show Reason",cliDisplayDescription:"Always show the reason field in embeds, even when there is no reason provided."})}, {key:"emojiStyle",checker:new api.ODCheckerStringStructure("opendiscord:emoji-style",{choices:["before","after","double","disabled"],cliDisplayName:"Emoji Style",cliDisplayDescription:"Choose how the bot will display emojis in message titles. (Visit docs for more info)"})}, - {key:"pinEmoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:pin-emoji",1,1,false,{cliDisplayName:"Pin Emoji",cliDisplayDescription:"The emoji used when pinning tickets. This is '๐Ÿ“Œ' by default."})}, + {key:"pinEmoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:pin-emoji",0,1,false,{cliDisplayName:"Pin Emoji",cliDisplayDescription:"The emoji used when pinning tickets. This is '๐Ÿ“Œ' by default. Leave empty to disable."})}, + {key:"closeEmoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:close-emoji",0,1,false,{cliDisplayName:"Pin Emoji",cliDisplayDescription:"The emoji used when closing tickets. This is '๐Ÿ”’' by default. Leave empty to disable."})}, {key:"replyOnTicketCreation",checker:new api.ODCheckerBooleanStructure("opendiscord:reply-on-ticket-creation",{cliDisplayName:"Reply On Ticket Creation",cliDisplayDescription:"When enabled, the bot will send an ephemeral reply in the channel of the panel when creating a ticket."})}, {key:"replyOnReactionRole",checker:new api.ODCheckerBooleanStructure("opendiscord:reply-on-reaction-role",{cliDisplayName:"Reply On Reaction Role",cliDisplayDescription:"When enabled, the bot will send an ephemeral reply in the channel of the panel when using a role button."})}, @@ -272,11 +289,7 @@ export const defaultGeneralStructure = new api.ODCheckerObjectStructure("opendis {key:"enableTicketDeleteButtons",checker:new api.ODCheckerBooleanStructure("opendiscord:enable-ticket-delete-buttons",{cliDisplayName:"Enable Ticket Delete Buttons",cliDisplayDescription:"Enable/disable buttons for deleting a ticket. Be aware that this doesn't disable the command!"})}, {key:"enableTicketActionWithReason",checker:new api.ODCheckerBooleanStructure("opendiscord:enable-ticket-action-with-reason",{cliDisplayName:"Enable Ticket Action With Reason",cliDisplayDescription:"Enable/disable buttons to write an additional reason for all ticket actions."})}, {key:"enableDeleteWithoutTranscript",checker:new api.ODCheckerBooleanStructure("opendiscord:enable-delete-without-transcript",{cliDisplayName:"Enable Delete Without Transcript",cliDisplayDescription:"Enable/disable the ability to delete tickets without a transcript."})}, - - {key:"logs",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:system-logs",{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure("opendiscord:system-logs",{children:[ - {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:logs-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable discord logs in a discord channel."})}, - {key:"channel",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:logs-channel","channel",false,[],{cliDisplayName:"Log Channel",cliDisplayDescription:"The ID of the discord channel to log messages to. You can configure the messages somewhere else."})}, - ],cliDisplayName:"Discord Logs",cliDisplayDescription:"Manage everything related to logs in a discord channel."}),cliDisplayName:"Discord Logs",cliDisplayDescription:"Manage everything related to logs in a discord channel."})}, + {key:"enableCreateTicketForOtherUser",checker:new api.ODCheckerBooleanStructure("opendiscord:enable-create-for-other-user",{cliDisplayName:"Enable Create ticket for other user",cliDisplayDescription:"Enable/disable the ability for admins to create a ticket for another user."})}, {key:"limits",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:limits",{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure("opendiscord:limits",{children:[ {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:limits-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable global limits."})}, @@ -287,42 +300,66 @@ export const defaultGeneralStructure = new api.ODCheckerObjectStructure("opendis {key:"channelTopic",checker:new api.ODCheckerObjectStructure("opendiscord:channel-topic",{children:[ {key:"showOptionName",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-option-name",{cliDisplayName:"Show Option Name",cliDisplayDescription:"Show the option name in the channel topic."})}, {key:"showOptionDescription",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-option-description",{cliDisplayName:"Show Option Description",cliDisplayDescription:"Show the option description in the channel topic."})}, - {key:"showOptionTopic",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-option-topic",{cliDisplayName:"Show Option Topic",cliDisplayDescription:"Show the option topic text in the channel topic (configured in the options.json config)."})}, + {key:"showOptionTopic",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-option-topic",{cliDisplayName:"Show Option Topic",cliDisplayDescription:"Show the option topic text in the channel topic (configured in the options.jsonc config)."})}, {key:"showPriority",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-priority",{cliDisplayName:"Show Priority",cliDisplayDescription:"Show the current priority in the channel topic (auto-updated)."})}, {key:"showClosed",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-closed",{cliDisplayName:"Show Closed Status",cliDisplayDescription:"Show the current close/reopen status in the channel topic (auto-updated)."})}, {key:"showClaimed",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-claimed",{cliDisplayName:"Show Claimed Status",cliDisplayDescription:"Show the current claim status in the channel topic (auto-updated)."})}, {key:"showPinned",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-pinned",{cliDisplayName:"Show Pinned Status",cliDisplayDescription:"Show the current pin status in the channel topic (auto-updated)."})}, {key:"showCreator",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-creator",{cliDisplayName:"Show Creator",cliDisplayDescription:"Show the creator of the ticket in the channel topic (auto-updated on transfer)."})}, {key:"showParticipants",checker:new api.ODCheckerBooleanStructure("opendiscord:topic-show-participants",{cliDisplayName:"Show Participants",cliDisplayDescription:"Show the first 5 participants of the ticket in the channel topic (auto-updated)."})}, - ],cliDisplayName:"Channel Topic",cliDisplayDescription:"Manage stats and text of ticket channel topics."})}, - {key:"permissions",checker:new api.ODCheckerObjectStructure("opendiscord:system-permissions",{children:[ - {key:"help",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-help","role",false,["admin","everyone","none"],{cliDisplayName:"Help",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"panel",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-panel","role",false,["admin","everyone","none"],{cliDisplayName:"Panel",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"ticket",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-ticket","role",false,["admin","everyone","none"],{cliDisplayName:"Ticket",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"close",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-close","role",false,["admin","everyone","none"],{cliDisplayName:"Close",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"delete",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-delete","role",false,["admin","everyone","none"],{cliDisplayName:"Delete",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"reopen",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-reopen","role",false,["admin","everyone","none"],{cliDisplayName:"Reopen",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"claim",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-claim","role",false,["admin","everyone","none"],{cliDisplayName:"Claim",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"unclaim",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-unclaim","role",false,["admin","everyone","none"],{cliDisplayName:"Unclaim",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"pin",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-pin","role",false,["admin","everyone","none"],{cliDisplayName:"Pin",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"unpin",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-unpin","role",false,["admin","everyone","none"],{cliDisplayName:"Unpin",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"move",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-move","role",false,["admin","everyone","none"],{cliDisplayName:"Move",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"rename",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-rename","role",false,["admin","everyone","none"],{cliDisplayName:"Rename",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"add",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-add","role",false,["admin","everyone","none"],{cliDisplayName:"Add User",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"remove",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-remove","role",false,["admin","everyone","none"],{cliDisplayName:"Remove User",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"blacklist",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-blacklist","role",false,["admin","everyone","none"],{cliDisplayName:"Blacklist",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"stats",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-stats","role",false,["admin","everyone","none"],{cliDisplayName:"Stats",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"clear",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-clear","role",false,["admin","everyone","none"],{cliDisplayName:"Clear Tickets",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"autoclose",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-autoclose","role",false,["admin","everyone","none"],{cliDisplayName:"Autoclose",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"autodelete",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-autodelete","role",false,["admin","everyone","none"],{cliDisplayName:"Autodelete",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"transfer",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-transfer","role",false,["admin","everyone","none"],{cliDisplayName:"Transfer",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"topic",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-topic","role",false,["admin","everyone","none"],{cliDisplayName:"Topic",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - {key:"priority",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:permissions-priority","role",false,["admin","everyone","none"],{cliDisplayName:"Priority",cliHideDescriptionInParent:true,cliDisplayDescription:"Set the permissions to 'everyone' for everyone, 'admin' for admin only, 'none' to disable or a custom discord role ID."})}, - ],cliDisplayName:"Permissions",cliDisplayDescription:"Manage all button & command permissions in the bot. (Visit docs for more info)"})}, + {key:"closedCategory",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:closed-category",{property:"enabled",enabledValue:true,ignoreCheckIfDisabled:true,checker:new api.ODCheckerObjectStructure("opendiscord:closed-category",{children:[ + {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:closed-category-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable closed category."})}, + {key:"categoryId",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:closed-category","category",true,[],{cliDisplayName:"Closed Category",cliDisplayDescription:"An additional category where tickets will be moved to when closed."})}, + ],cliDisplayName:"Closed Category",cliDisplayDescription:"An additional category where tickets will be moved to when closed."}),cliDisplayName:"Closed Category",cliDisplayDescription:"An additional category where tickets will be moved to when closed."})}, + + {key:"backupCategory",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:backup-category",{property:"enabled",enabledValue:true,ignoreCheckIfDisabled:true,checker:new api.ODCheckerObjectStructure("opendiscord:backup-category",{children:[ + {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:backup-category-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable backup category."})}, + {key:"categoryId",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:backup-category","category",true,[],{cliDisplayName:"Backup Category",cliDisplayDescription:"An additional category where tickets will be created in when the original category is full (50 channels)."})}, + ],cliDisplayName:"Backup Category",cliDisplayDescription:"An additional category where tickets will be created in when the original category is full (50 channels)."}),cliDisplayName:"Backup Category",cliDisplayDescription:"An additional category where tickets will be created in when the original category is full (50 channels)."})}, + + {key:"claimedCategories",checker:new api.ODCheckerArrayStructure("opendiscord:claimed-categories",{allowDoubles:false,allowedTypes:["object"],cliDisplayPropertyName:"claim category",propertyChecker:new api.ODCheckerObjectStructure("opendiscord:claimed-category",{children:[ + {key:"user",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:claimed-user","user",false,[],{cliDisplayName:"User",cliDisplayDescription:"The discord user ID of a ticket claimer."})}, + {key:"category",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:claimed-category","category",false,[],{cliDisplayName:"Category",cliDisplayDescription:"The discord category ID to move the ticket to."})} + ],cliDisplayName:"Claimed Category",cliDisplayDescription:"Move claimed tickets to the matching channel category of the user that claimed the ticket."}),cliDisplayName:"Claimed Categories",cliDisplayDescription:"Move claimed tickets to the matching channel category of the user that claimed the ticket."})}, + + ],cliDisplayName:"Ticket System",cliDisplayDescription:"Configure the 'Open Ticket' ticket system."})}, - {key:"messages",checker:new api.ODCheckerObjectStructure("opendiscord:system-permissions",{children:[ + //COMMAND PERMISSIONS + {key:"permissions",checker:new api.ODCheckerObjectStructure("opendiscord:permissions",{children:[ + {key:"help",checker:createPermissionStructure("opendiscord:permissions-help","Help")}, + {key:"panel",checker:createPermissionStructure("opendiscord:permissions-panel","Panel")}, + {key:"ticket",checker:createPermissionStructure("opendiscord:permissions-ticket","Ticket")}, + {key:"close",checker:createPermissionStructure("opendiscord:permissions-close","Close")}, + {key:"delete",checker:createPermissionStructure("opendiscord:permissions-delete","Delete")}, + {key:"reopen",checker:createPermissionStructure("opendiscord:permissions-reopen","Reopen")}, + {key:"claim",checker:createPermissionStructure("opendiscord:permissions-claim","Claim")}, + {key:"unclaim",checker:createPermissionStructure("opendiscord:permissions-unclaim","Unclaim")}, + {key:"pin",checker:createPermissionStructure("opendiscord:permissions-pin","Pin")}, + {key:"unpin",checker:createPermissionStructure("opendiscord:permissions-unpin","Unpin")}, + {key:"move",checker:createPermissionStructure("opendiscord:permissions-move","Move")}, + {key:"rename",checker:createPermissionStructure("opendiscord:permissions-rename","Rename")}, + {key:"add",checker:createPermissionStructure("opendiscord:permissions-add","Add User")}, + {key:"remove",checker:createPermissionStructure("opendiscord:permissions-remove","Remove User")}, + {key:"blacklist",checker:createPermissionStructure("opendiscord:permissions-blacklist","Blacklist")}, + {key:"stats",checker:createPermissionStructure("opendiscord:permissions-stats","Stats")}, + {key:"clear",checker:createPermissionStructure("opendiscord:permissions-clear","Clear Tickets")}, + {key:"autoclose",checker:createPermissionStructure("opendiscord:permissions-autoclose","Autoclose")}, + {key:"autodelete",checker:createPermissionStructure("opendiscord:permissions-autodelete","Autodelete")}, + {key:"transfer",checker:createPermissionStructure("opendiscord:permissions-transfer","Transfer")}, + {key:"topic",checker:createPermissionStructure("opendiscord:permissions-topic","Topic")}, + {key:"priority",checker:createPermissionStructure("opendiscord:permissions-priority","Priority")}, + {key:"transcripts",checker:createPermissionStructure("opendiscord:permissions-transcripts","Transcripts History")}, + ],cliDisplayName:"Permissions",cliDisplayDescription:"Manage all button & command permissions in the bot. (Visit docs for more info)"})}, + + //LOGS + {key:"logs",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:logs",{property:"enabled",enabledValue:true,ignoreCheckIfDisabled:true,checker:new api.ODCheckerObjectStructure("opendiscord:logs",{children:[ + {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:logs-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable discord logs in a discord channel."})}, + {key:"channel",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:logs-channel","channel",false,[],{cliDisplayName:"Log Channel",cliDisplayDescription:"The log message channel ID."})}, + + //LOG MESSAGES + {key:"logMessages",checker:new api.ODCheckerObjectStructure("opendiscord:log-messages",{children:[ {key:"creation",checker:createMsgStructure("opendiscord:msg-creation","Ticket Created")}, {key:"closing",checker:createMsgStructure("opendiscord:msg-closing","Ticket Closed")}, {key:"deleting",checker:createMsgStructure("opendiscord:msg-deleting","Ticket Deleted")}, @@ -338,22 +375,23 @@ export const defaultGeneralStructure = new api.ODCheckerObjectStructure("opendis {key:"topicChange",checker:createMsgStructure("opendiscord:msg-topic-change","Topic Changed")}, {key:"priorityChange",checker:createMsgStructure("opendiscord:msg-priority-change","Priority Changed")}, {key:"reactionRole",checker:createMsgStructure("opendiscord:msg-reaction-role","Reaction Role")}, - ],cliDisplayName:"Messages",cliDisplayDescription:"Manage all messages & DM's for each action of the bot. (Visit docs for more info)"})}, - ],cliDisplayName:"System",cliDisplayDescription:"Configure everything related to the ticket system."})} + ],cliDisplayName:"Log Messages",cliDisplayDescription:"Manage all messages & DM's for each action of the bot. (Visit docs for more info)"})}, + ],cliDisplayName:"Discord Logs",cliDisplayDescription:"Manage the 'Open Ticket' logs channel."}),cliDisplayName:"Discord Logs",cliDisplayDescription:"Manage the 'Open Ticket' logs channel."})}, + ],cliDisplayName:"General",cliDisplayDescription:"General settings for the bot."}) export const defaultOptionsStructure = new api.ODCheckerArrayStructure("opendiscord:options",{allowedTypes:["object"],cliDisplayPropertyName:"option",propertyChecker:new api.ODCheckerObjectSwitchStructure("opendiscord:options",{objects:[ //TICKET {name:"Ticket",priority:0,properties:[{key:"type",value:"ticket"}],checker:new api.ODCheckerObjectStructure("opendiscord:ticket",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],cliInitSkipKeys:["readonlyAdmins"],children:[ - {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:ticket-id","openticket","option-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this ticket option. Used in panels."})}, - {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:ticket-name",{minLength:2,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this ticket option."})}, - {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:ticket-description",{maxLength:256,cliDisplayName:"Description",cliDisplayDescription:"The description of this ticket option."})}, + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:id","openticket","option-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this ticket option. Used in panels."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:name",{minLength:2,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this ticket option."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:description",{maxLength:256,cliDisplayName:"Description",cliDisplayDescription:"The description of this ticket option."})}, //TICKET BUTTON - {key:"button",checker:new api.ODCheckerObjectStructure("opendiscord:ticket-button",{children:[ - {key:"emoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:ticket-button-emoji",0,1,true,{cliDisplayName:"Emoji",cliDisplayDescription:"The emoji of the button. At least 1 of 2 (emoji/label) must be provided."})}, - {key:"label",checker:new api.ODCheckerStringStructure("opendiscord:ticket-button-label",{maxLength:80,cliDisplayName:"Label",cliDisplayDescription:"The label of the button. At least 1 of 2 (emoji/label) must be provided."})}, - {key:"color",checker:new api.ODCheckerStringStructure("opendiscord:ticket-button-color",{choices:["gray","red","green","blue"],cliDisplayName:"Color",cliDisplayDescription:"The color of the button. Does not apply when using a dropdown panel."})}, + {key:"button",checker:new api.ODCheckerObjectStructure("opendiscord:button",{children:[ + {key:"emoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:button-emoji",0,1,true,{cliDisplayName:"Emoji",cliDisplayDescription:"The emoji of the button. At least 1 of 2 (emoji/label) must be provided."})}, + {key:"label",checker:new api.ODCheckerStringStructure("opendiscord:button-label",{maxLength:80,cliDisplayName:"Label",cliDisplayDescription:"The label of the button. At least 1 of 2 (emoji/label) must be provided."})}, + {key:"color",checker:new api.ODCheckerStringStructure("opendiscord:button-color",{choices:["gray","red","green","blue"],cliDisplayName:"Color",cliDisplayDescription:"The color of the button. Does not apply when using a dropdown panel."})}, ],custom:(checker,value,locationTrace,locationId,locationDocs) => { const lt = checker.locationTraceDeref(locationTrace) //check if emoji & label exists @@ -369,7 +407,7 @@ export const defaultOptionsStructure = new api.ODCheckerArrayStructure("opendisc {key:"ticketAdmins",checker:new api.ODCheckerCustomStructure_DiscordIdArray("opendiscord:ticket-ticket-admins","role",[],{allowDoubles:false,cliDisplayPropertyName:"ticket admin role",cliDisplayName:"Ticket Admin Roles",cliDisplayDescription:"A list of role IDs that are only able to interact with this ticket option."},{cliDisplayName:"Ticket Admin Role",cliDisplayDescription:"The discord role ID of a ticket admin."})}, {key:"readonlyAdmins",checker:new api.ODCheckerCustomStructure_DiscordIdArray("opendiscord:ticket-readonly-admins","role",[],{allowDoubles:false,cliInitDefaultValue:[],cliDisplayPropertyName:"read-only ticket admin role",cliDisplayName:"Readonly Admin Roles",cliDisplayDescription:"A list of role IDs that are only able to read this ticket option."},{cliDisplayName:"Readonly Admin Role",cliDisplayDescription:"The discord role ID of a readonly admin."})}, {key:"allowCreationByBlacklistedUsers",checker:new api.ODCheckerBooleanStructure("opendiscord:ticket-allow-blacklisted-users",{cliDisplayName:"Allow Creation By Blacklisted Users",cliDisplayDescription:"When enabled, the blacklist doesn't apply to this ticket option/type and users are still able to create a ticket."})}, - {key:"questions",checker:new api.ODCheckerCustomStructure_UniqueIdArray("opendiscord:option-questions","openticket","question-ids","question-ids-used",{allowDoubles:false,maxLength:5,cliDisplayPropertyName:"question",cliDisplayName:"Questions",cliDisplayDescription:"A list of valid question IDs to ask before creating this ticket."},{cliDisplayName:"Question ID",cliDisplayDescription:"A valid question ID from the questions.json config.",cliAutocompleteFunc:async () => { + {key:"questions",checker:new api.ODCheckerCustomStructure_UniqueIdArray("opendiscord:option-questions","openticket","question-ids","question-ids-used",{allowDoubles:false,maxLength:5,cliDisplayPropertyName:"question",cliDisplayName:"Questions",cliDisplayDescription:"A list of valid question IDs to ask before creating this ticket."},{cliDisplayName:"Question ID",cliDisplayDescription:"A valid question ID from the questions.jsonc config.",cliAutocompleteFunc:async () => { const uncheckedRawData = opendiscord.configs.get("opendiscord:questions").data if (!Array.isArray(uncheckedRawData)) return null const idList = uncheckedRawData.filter((option) => typeof option == "object" && typeof option["id"] == "string").map((option) => option.id) @@ -380,15 +418,8 @@ export const defaultOptionsStructure = new api.ODCheckerArrayStructure("opendisc {key:"channel",checker:new api.ODCheckerObjectStructure("opendiscord:ticket-channel",{cliInitSkipKeys:["backupCategory","claimedCategory"],children:[ {key:"prefix",checker:new api.ODCheckerStringStructure("opendiscord:ticket-channel-prefix",{maxLength:25,regex:/^[^\s]*$/,cliDisplayName:"Prefix",cliDisplayDescription:"The prefix of the name of the ticket channel. (e.g. 'question-')"})}, {key:"suffix",checker:new api.ODCheckerStringStructure("opendiscord:ticket-channel-suffix",{choices:["user-name","user-nickname","user-id","random-number","random-hex","counter-dynamic","counter-fixed"],cliDisplayName:"Suffix",cliDisplayDescription:"The suffix mode to use. The number/text will be appended after the prefix."})}, - {key:"category",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:ticket-channel-category","category",true,[],{cliDisplayName:"Category",cliDisplayDescription:"The category the ticket will be created in. Leave empty for no category."})}, - {key:"closedCategory",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:ticket-channel-closed-category","category",true,[],{cliDisplayName:"Closed Category",cliDisplayDescription:"An additional category where the ticket will be moved to when closed."})}, - {key:"backupCategory",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:ticket-channel-backup-category","category",true,[],{cliDisplayName:"Backup Category",cliDisplayDescription:"An additional category where the ticket will be created in when the primary category is full (50 channels)."})}, - {key:"claimedCategory",checker:new api.ODCheckerArrayStructure("opendiscord:ticket-channel-claimed-category",{allowDoubles:false,allowedTypes:["object"],cliDisplayPropertyName:"claim category",propertyChecker:new api.ODCheckerObjectStructure("opendiscord:ticket-channel-claimed-category",{children:[ - {key:"user",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:ticket-channel-claimed-user","user",false,[],{cliDisplayName:"User",cliDisplayDescription:"A discord user ID of the ticket claimer."})}, - {key:"category",checker:new api.ODCheckerCustomStructure_DiscordId("opendiscord:ticket-channel-claimed-category","category",false,[],{cliDisplayName:"Category",cliDisplayDescription:"A discord category ID to move the ticket to."})} - ],cliDisplayName:"Claimed Category",cliDisplayDescription:"A collection of a user ID and a category ID. The ticket will be moved to the category when this user claims the ticket."}),cliDisplayName:"Claimed Categories",cliDisplayDescription:"Add categories to move the ticket to when a user claims a ticket."})}, - {key:"topic",checker:new api.ODCheckerStringStructure("opendiscord:ticket-channel-topic",{cliDisplayName:"Channel Topic",cliDisplayDescription:"The topic text of the ticket channel. Visible in the discord client when general.json 'channelTopic'.'showOptionTopic' is enabled."})}, + {key:"topic",checker:new api.ODCheckerStringStructure("opendiscord:ticket-channel-topic",{cliDisplayName:"Channel Topic",cliDisplayDescription:"The topic text of the ticket channel. Visible in the discord client when general.jsonc 'channelTopic'.'showOptionTopic' is enabled."})}, ],cliDisplayName:"Channel",cliDisplayDescription:"Manage all settings related to the ticket channel and categories."})}, //DM MESSAGE @@ -445,14 +476,14 @@ export const defaultOptionsStructure = new api.ODCheckerArrayStructure("opendisc //WEBSITE {name:"Website",priority:0,properties:[{key:"type",value:"website"}],checker:new api.ODCheckerObjectStructure("opendiscord:website",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ - {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:website-id","openticket","option-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this website option. Used in panels."})}, - {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:website-name",{minLength:2,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this website option."})}, - {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:website-description",{maxLength:256,cliDisplayName:"Description",cliDisplayDescription:"The description of this website option."})}, + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:id","openticket","option-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this website option. Used in panels."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:name",{minLength:2,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this website option."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:description",{maxLength:256,cliDisplayName:"Description",cliDisplayDescription:"The description of this website option."})}, //WEBSITE BUTTON - {key:"button",checker:new api.ODCheckerObjectStructure("opendiscord:ticket-button",{children:[ - {key:"emoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:ticket-button-emoji",0,1,true,{cliDisplayName:"Emoji",cliDisplayDescription:"The emoji of the button. At least 1 of 2 (emoji/label) must be provided."})}, - {key:"label",checker:new api.ODCheckerStringStructure("opendiscord:ticket-button-label",{maxLength:80,cliDisplayName:"Label",cliDisplayDescription:"The label of the button. At least 1 of 2 (emoji/label) must be provided."})}, + {key:"button",checker:new api.ODCheckerObjectStructure("opendiscord:button",{children:[ + {key:"emoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:button-emoji",0,1,true,{cliDisplayName:"Emoji",cliDisplayDescription:"The emoji of the button. At least 1 of 2 (emoji/label) must be provided."})}, + {key:"label",checker:new api.ODCheckerStringStructure("opendiscord:button-label",{maxLength:80,cliDisplayName:"Label",cliDisplayDescription:"The label of the button. At least 1 of 2 (emoji/label) must be provided."})}, ],custom:(checker,value,locationTrace,locationId,locationDocs) => { const lt = checker.locationTraceDeref(locationTrace) //check if emoji & label exists @@ -470,15 +501,15 @@ export const defaultOptionsStructure = new api.ODCheckerArrayStructure("opendisc //REACTION ROLES {name:"Reaction Role",priority:0,properties:[{key:"type",value:"role"}],checker:new api.ODCheckerObjectStructure("opendiscord:role",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ - {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:role-id","openticket","option-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this role option. Used in panels."})}, - {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:role-name",{minLength:2,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this role option."})}, - {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:role-description",{maxLength:256,cliDisplayName:"Description",cliDisplayDescription:"The description of this role option."})}, + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:id","openticket","option-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this role option. Used in panels."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:name",{minLength:2,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this role option."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:description",{maxLength:256,cliDisplayName:"Description",cliDisplayDescription:"The description of this role option."})}, //ROLE BUTTON - {key:"button",checker:new api.ODCheckerObjectStructure("opendiscord:ticket-button",{children:[ - {key:"emoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:ticket-button-emoji",0,1,true,{cliDisplayName:"Emoji",cliDisplayDescription:"The emoji of the button. At least 1 of 2 (emoji/label) must be provided."})}, - {key:"label",checker:new api.ODCheckerStringStructure("opendiscord:ticket-button-label",{maxLength:80,cliDisplayName:"Label",cliDisplayDescription:"The label of the button. At least 1 of 2 (emoji/label) must be provided."})}, - {key:"color",checker:new api.ODCheckerStringStructure("opendiscord:ticket-button-color",{choices:["gray","red","green","blue"],cliDisplayName:"Color",cliDisplayDescription:"The color of the button. Does not apply when using a dropdown panel."})}, + {key:"button",checker:new api.ODCheckerObjectStructure("opendiscord:button",{children:[ + {key:"emoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:button-emoji",0,1,true,{cliDisplayName:"Emoji",cliDisplayDescription:"The emoji of the button. At least 1 of 2 (emoji/label) must be provided."})}, + {key:"label",checker:new api.ODCheckerStringStructure("opendiscord:button-label",{maxLength:80,cliDisplayName:"Label",cliDisplayDescription:"The label of the button. At least 1 of 2 (emoji/label) must be provided."})}, + {key:"color",checker:new api.ODCheckerStringStructure("opendiscord:button-color",{choices:["gray","red","green","blue"],cliDisplayName:"Color",cliDisplayDescription:"The color of the button. Does not apply when using a dropdown panel."})}, ],custom:(checker,value,locationTrace,locationId,locationDocs) => { const lt = checker.locationTraceDeref(locationTrace) //check if emoji & label exists @@ -496,13 +527,52 @@ export const defaultOptionsStructure = new api.ODCheckerArrayStructure("opendisc {key:"removeRolesOnAdd",checker:new api.ODCheckerCustomStructure_DiscordIdArray("opendiscord:role-remove-roles","role",[],{allowDoubles:false,cliDisplayPropertyName:"role",cliDisplayName:"Remove Roles On Add",cliDisplayDescription:"An additional list of roles to remove when the roles of this option are added. (Can be used to select between roles)"},{cliDisplayName:"Remove Role",cliDisplayDescription:"The discord role ID you want to remove when other roles are added."})}, {key:"addOnMemberJoin",checker:new api.ODCheckerBooleanStructure("opendiscord:role-add-on-join",{cliDisplayName:"Add On Member Join",cliDisplayDescription:"Automatically add these roles to a user when joining the server."})}, ],cliDisplayName:"Reaction Role Option",cliDisplayDescription:"Manage all settings of this reaction role option."})}, + + //SUB-PANEL + {name:"Reaction Role",priority:0,properties:[{key:"type",value:"sub-panel"}],checker:new api.ODCheckerObjectStructure("opendiscord:sub-panel",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:id","openticket","option-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this sub-panel option. Used in panels."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:name",{minLength:2,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this sub-panel option."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:description",{maxLength:256,cliDisplayName:"Description",cliDisplayDescription:"The description of this sub-panel option."})}, + + //SUB-PANEL BUTTON + {key:"button",checker:new api.ODCheckerObjectStructure("opendiscord:button",{children:[ + {key:"emoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:button-emoji",0,1,true,{cliDisplayName:"Emoji",cliDisplayDescription:"The emoji of the button. At least 1 of 2 (emoji/label) must be provided."})}, + {key:"label",checker:new api.ODCheckerStringStructure("opendiscord:button-label",{maxLength:80,cliDisplayName:"Label",cliDisplayDescription:"The label of the button. At least 1 of 2 (emoji/label) must be provided."})}, + {key:"color",checker:new api.ODCheckerStringStructure("opendiscord:button-color",{choices:["gray","red","green","blue"],cliDisplayName:"Color",cliDisplayDescription:"The color of the button. Does not apply when using a dropdown panel."})}, + ],custom:(checker,value,locationTrace,locationId,locationDocs) => { + const lt = checker.locationTraceDeref(locationTrace) + //check if emoji & label exists + if (typeof value != "object") return false + else if (value && value["emoji"].length < 1 && value["label"].length < 1){ + //label & emoji are both empty + checker.createMessage("opendiscord:invalid-button","error",`This button needs to have at least an "emoji" or "label"!`,lt,null,[`"emoji"`,`"label"`],locationId,locationDocs) + return false + }else return true + },cliDisplayName:"Button",cliDisplayDescription:"Customise the button layout of this sub-panel option."})}, + + //SUB-PANEL SETTINGS + {key:"subPanelId",checker:new api.ODCheckerStringStructure("ot-footers:panel-id",{custom:(checker,value,locationTrace,locationId,locationDocs) => { + const lt = checker.locationTraceDeref(locationTrace) + if (typeof value != "string") return false + + if (getUnsafePanelIds().includes(value)){ + //exists + return true + }else{ + //doesn't exist + checker.createMessage("opendiscord:id-non-existent","error",`The panel id "${value}" doesn't exist!`,lt,null,[`"${value}"`],locationId,locationDocs) + return false + } + }})}, + ],cliDisplayName:"Sub-Panel Option",cliDisplayDescription:"Manage all settings of this sub-panel option."})}, + ],cliDisplayName:"Option",cliDisplayDescription:"Manage an option of one of the 3 types: ticket, website, role."}),cliDisplayName:"Options",cliDisplayDescription:"A list of all options in the bot. Here you can add, modify & remove ticket types, website buttons & reaction roles!"}) export const defaultPanelsStructure = new api.ODCheckerArrayStructure("opendiscord:panels",{allowedTypes:["object"],cliDisplayPropertyName:"panel",propertyChecker:new api.ODCheckerObjectStructure("opendiscord:panels",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","dropdown"],children:[ {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:panel-id","openticket","panel-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this panel. Used in the /panel command."})}, {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:panel-name",{minLength:3,maxLength:50,cliDisplayName:"Name",cliDisplayDescription:"The name of this panel."})}, {key:"dropdown",checker:new api.ODCheckerBooleanStructure("opendiscord:panel-dropdown",{cliDisplayName:"Dropdown",cliDisplayDescription:"Decide whether to use buttons or a dropdown in the panel. Dropdowns only support options of the 'ticket' type!"})}, - {key:"options",checker:new api.ODCheckerCustomStructure_UniqueIdArray("opendiscord:panel-options","openticket","option-ids","option-ids-used",{allowDoubles:false,minLength:1,maxLength:25,cliDisplayPropertyName:"option",cliDisplayName:"Options",cliDisplayDescription:"A list of valid option IDs to show in this panel."},{cliDisplayName:"Option ID",cliDisplayDescription:"A valid option ID from the options.json config.",cliAutocompleteFunc:async () => { + {key:"options",checker:new api.ODCheckerCustomStructure_UniqueIdArray("opendiscord:panel-options","openticket","option-ids","option-ids-used",{allowDoubles:false,minLength:1,maxLength:25,cliDisplayPropertyName:"option",cliDisplayName:"Options",cliDisplayDescription:"A list of valid option IDs to show in this panel."},{cliDisplayName:"Option ID",cliDisplayDescription:"A valid option ID from the options.jsonc config.",cliAutocompleteFunc:async () => { const uncheckedRawData = opendiscord.configs.get("opendiscord:options").data if (!Array.isArray(uncheckedRawData)) return null const idList = uncheckedRawData.filter((option) => typeof option == "object" && typeof option["id"] == "string").map((option) => option.id) @@ -516,6 +586,8 @@ export const defaultPanelsStructure = new api.ODCheckerArrayStructure("opendisco //SETTINGS {key:"settings",checker:new api.ODCheckerObjectStructure("opendiscord:panel-settings",{cliInitSkipKeys:["dropdownPlaceholder","describeOptionsCustomTitle"],children:[ {key:"dropdownPlaceholder",checker:new api.ODCheckerStringStructure("opendiscord:panel-settings-placeholder",{maxLength:100,cliInitDefaultValue:"Create a ticket!",cliDisplayName:"Dropdown Placeholder",cliDisplayDescription:"Configure the text displayed in the dropdown when nothing is selected."})}, + {key:"maximumButtonsPerRow",checker:new api.ODCheckerNumberStructure("opendiscord:panel-settings-row-amount",{min:1,max:5,floatAllowed:false,cliInitDefaultValue:5,cliDisplayName:"Maximum Buttons Per Row",cliDisplayDescription:"Set the maximum amount of buttons in a single row before starting a new one."})}, + {key:"enableMaxTicketsWarningInText",checker:new api.ODCheckerBooleanStructure("opendiscord:panel-settings-maxtickets-text",{cliDisplayName:"Enable Max Tickets Warning (Text)",cliDisplayDescription:"Enable/disable the warning which shows how many tickets you can create in the text contents of the panel."})}, {key:"enableMaxTicketsWarningInEmbed",checker:new api.ODCheckerBooleanStructure("opendiscord:panel-settings-maxtickets-embed",{cliDisplayName:"Enable Max Tickets Warning (Embed)",cliDisplayDescription:"Enable/disable the warning which shows how many tickets you can create in the embed of the panel."})}, @@ -527,20 +599,95 @@ export const defaultPanelsStructure = new api.ODCheckerArrayStructure("opendisco ],cliDisplayName:"Settings",cliDisplayDescription:"Manage additional settings & customisability for this panel."})}, ],cliDisplayName:"Panel",cliDisplayDescription:"Manage, customise and configure a panel to your preference."}),cliDisplayName:"Panels",cliDisplayDescription:"A list of all panels in the bot. Here you can add, modify & remove existing panels or customise them to your preference."}) -export const defaultQuestionsStructure = new api.ODCheckerArrayStructure("opendiscord:questions",{allowedTypes:["object"],cliDisplayPropertyName:"question",propertyChecker:new api.ODCheckerObjectStructure("opendiscord:questions",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ - {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this question. Used in ticket options."})}, - {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:question-name",{minLength:3,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this question."})}, - {key:"type",checker:new api.ODCheckerStringStructure("opendiscord:question-type",{choices:["short","paragraph"],cliDisplayName:"Type",cliDisplayDescription:"The type of this question (short/paragraph)."})}, - - {key:"required",checker:new api.ODCheckerBooleanStructure("opendiscord:question-required",{cliDisplayName:"Required",cliDisplayDescription:"Is this question required? If not, it can be left empty."})}, - {key:"placeholder",checker:new api.ODCheckerStringStructure("opendiscord:question-placeholder",{maxLength:100,cliDisplayName:"Placeholder",cliDisplayDescription:"The placeholder to show in the field when nothing has been written yet."})}, - - {key:"length",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:question-length",{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure("opendiscord:question-length",{children:[ - {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:question-length-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable length validation for this question."})}, - {key:"min",checker:new api.ODCheckerNumberStructure("opendiscord:question-length-min",{min:0,max:1024,negativeAllowed:false,floatAllowed:false,cliDisplayName:"Min Length",cliDisplayDescription:"The minimum amount of characters required."})}, - {key:"max",checker:new api.ODCheckerNumberStructure("opendiscord:question-length-max",{min:1,max:1024,negativeAllowed:false,floatAllowed:false,cliInitDefaultValue:100,cliDisplayName:"Max Length",cliDisplayDescription:"The maximum amount of characters allowed."})}, - ],cliDisplayName:"Length Validation",cliDisplayDescription:"Add length validation to the question. This way, the contents must be at least/most ... characters."}),cliDisplayName:"Length Validation",cliDisplayDescription:"Add length validation to the question. This way, the contents must be at least/most ... characters."})}, -],cliDisplayName:"Question",cliDisplayDescription:"Manage, customise and configure a question to your preference."}),cliDisplayName:"Questions",cliDisplayDescription:"A list of all questions in the bot. Here you can add, modify & remove existing questions or customise them to your preference."}) +export const defaultQuestionsStructure = new api.ODCheckerArrayStructure("opendiscord:questions",{allowedTypes:["object"],cliDisplayPropertyName:"question",propertyChecker:new api.ODCheckerObjectSwitchStructure("opendiscord:options",{objects:[ + //SHORT QUESTION + {name:"Short Question",priority:0,properties:[{key:"type",value:"short"}],checker:new api.ODCheckerObjectStructure("opendiscord:short-question",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this question. Used in ticket options."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:question-name",{minLength:3,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this question."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:question-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this question."})}, + {key:"required",checker:new api.ODCheckerBooleanStructure("opendiscord:question-required",{cliDisplayName:"Required",cliDisplayDescription:"Is this question required? If not, it can be left empty."})}, + + {key:"placeholder",checker:new api.ODCheckerStringStructure("opendiscord:question-placeholder",{maxLength:100,cliDisplayName:"Placeholder",cliDisplayDescription:"The placeholder to show in the field when nothing has been written yet."})}, + + {key:"length",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:question-length",{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure("opendiscord:question-length",{children:[ + {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:question-length-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable length validation for this question."})}, + {key:"min",checker:new api.ODCheckerNumberStructure("opendiscord:question-length-min",{min:0,max:1024,negativeAllowed:false,floatAllowed:false,cliDisplayName:"Min Length",cliDisplayDescription:"The minimum amount of characters required."})}, + {key:"max",checker:new api.ODCheckerNumberStructure("opendiscord:question-length-max",{min:1,max:1024,negativeAllowed:false,floatAllowed:false,cliInitDefaultValue:100,cliDisplayName:"Max Length",cliDisplayDescription:"The maximum amount of characters allowed."})}, + ],cliDisplayName:"Length Validation",cliDisplayDescription:"Add length validation to the question. This way, the contents must be at least/most ... characters."}),cliDisplayName:"Length Validation",cliDisplayDescription:"Add length validation to the question. This way, the contents must be at least/most ... characters."})}, + ],cliDisplayName:"Short Question",cliDisplayDescription:"Manage, customise and configure the short question to your preference."})}, + + //PARAGRAPH QUESTION + {name:"Paragraph Question",priority:0,properties:[{key:"type",value:"paragraph"}],checker:new api.ODCheckerObjectStructure("opendiscord:paragraph-question",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this question. Used in ticket options."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:question-name",{minLength:3,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this question."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:question-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this question."})}, + {key:"required",checker:new api.ODCheckerBooleanStructure("opendiscord:question-required",{cliDisplayName:"Required",cliDisplayDescription:"Is this question required? If not, it can be left empty."})}, + + {key:"placeholder",checker:new api.ODCheckerStringStructure("opendiscord:question-placeholder",{maxLength:100,cliDisplayName:"Placeholder",cliDisplayDescription:"The placeholder to show in the field when nothing has been written yet."})}, + + {key:"length",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:question-length",{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure("opendiscord:question-length",{children:[ + {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:question-length-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable length validation for this question."})}, + {key:"min",checker:new api.ODCheckerNumberStructure("opendiscord:question-length-min",{min:0,max:1024,negativeAllowed:false,floatAllowed:false,cliDisplayName:"Min Length",cliDisplayDescription:"The minimum amount of characters required."})}, + {key:"max",checker:new api.ODCheckerNumberStructure("opendiscord:question-length-max",{min:1,max:1024,negativeAllowed:false,floatAllowed:false,cliInitDefaultValue:100,cliDisplayName:"Max Length",cliDisplayDescription:"The maximum amount of characters allowed."})}, + ],cliDisplayName:"Length Validation",cliDisplayDescription:"Add length validation to the question. This way, the contents must be at least/most ... characters."}),cliDisplayName:"Length Validation",cliDisplayDescription:"Add length validation to the question. This way, the contents must be at least/most ... characters."})}, + ],cliDisplayName:"Paragraph Question",cliDisplayDescription:"Manage, customise and configure the paragraph question to your preference."})}, + + //TEXT DISPLAY QUESTION + {name:"Text Display Question",priority:0,properties:[{key:"type",value:"text-display"}],checker:new api.ODCheckerObjectStructure("opendiscord:text-display-question",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this text display. Used in ticket options."})}, + {key:"textContents",checker:new api.ODCheckerStringStructure("opendiscord:text-contents",{minLength:1,maxLength:2048,cliDisplayName:"Text Contents",cliDisplayDescription:"The text contents to show in the modal."})}, + ],cliDisplayName:"Text Display Question",cliDisplayDescription:"Manage, customise and configure the text display question to your preference."})}, + + //DROPDOWN QUESTION + {name:"Dropdown Question",priority:0,properties:[{key:"type",value:"dropdown"}],checker:new api.ODCheckerObjectStructure("opendiscord:dropdown-question",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this question. Used in ticket options."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:question-name",{minLength:3,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this question."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:question-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this question."})}, + {key:"required",checker:new api.ODCheckerBooleanStructure("opendiscord:question-required",{cliDisplayName:"Required",cliDisplayDescription:"Is this question required? If not, it can be left empty."})}, + + {key:"placeholder",checker:new api.ODCheckerStringStructure("opendiscord:question-placeholder",{maxLength:100,cliDisplayName:"Placeholder",cliDisplayDescription:"The placeholder to show in the field when nothing has been written yet."})}, + {key:"choices",checker:new api.ODCheckerArrayStructure("opendiscord:choices",{allowedTypes:["object"],minLength:1,maxLength:25,propertyChecker:new api.ODCheckerObjectStructure("opendiscord:choice",{children:[ + {key:"title",checker:new api.ODCheckerStringStructure("opendiscord:choice-title",{minLength:1,maxLength:100,cliDisplayName:"Title",cliDisplayDescription:"The title of this choice."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:choice-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this choice."})}, + {key:"emoji",checker:new api.ODCheckerCustomStructure_EmojiString("opendiscord:choice-emoji",0,1,true,{cliDisplayName:"Emoji",cliDisplayDescription:"The emoji of the choice. Leave empty to disable."})} + ],cliDisplayName:"Choice",cliDisplayDescription:"A choice for this dropdown question."}),cliDisplayName:"Choices",cliDisplayPropertyName:"choice",cliDisplayDescription:"Manage all available choices of this dropdown question."})} + ],cliDisplayName:"Dropdown Question",cliDisplayDescription:"Manage, customise and configure the dropdown question to your preference."})}, + + //RADIO SELECT QUESTION + {name:"Radio Select Question",priority:0,properties:[{key:"type",value:"radio-select"}],checker:new api.ODCheckerObjectStructure("opendiscord:radio-select-question",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this question. Used in ticket options."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:question-name",{minLength:3,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this question."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:question-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this question."})}, + {key:"required",checker:new api.ODCheckerBooleanStructure("opendiscord:question-required",{cliDisplayName:"Required",cliDisplayDescription:"Is this question required? If not, it can be left empty."})}, + + {key:"choices",checker:new api.ODCheckerArrayStructure("opendiscord:choices",{allowedTypes:["object"],minLength:2,maxLength:10,propertyChecker:new api.ODCheckerObjectStructure("opendiscord:choice",{children:[ + {key:"title",checker:new api.ODCheckerStringStructure("opendiscord:choice-title",{minLength:1,maxLength:100,cliDisplayName:"Title",cliDisplayDescription:"The title of this choice."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:choice-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this choice."})}, + {key:"selectedByDefault",checker:new api.ODCheckerBooleanStructure("opendiscord:choice-default",{cliDisplayName:"Selected By Default",cliDisplayDescription:"Should this choice be selected by default?"})} + ],cliDisplayName:"Choice",cliDisplayDescription:"A choice for this radio select question."}),cliDisplayName:"Choices",cliDisplayPropertyName:"choice",cliDisplayDescription:"Manage all available choices of this radio select question."})} + ],cliDisplayName:"Radio Select Question",cliDisplayDescription:"Manage, customise and configure the radio select question to your preference."})}, + + //CHECKBOX SELECT QUESTION + {name:"Checkbox Select Question",priority:0,properties:[{key:"type",value:"checkbox-select"}],checker:new api.ODCheckerObjectStructure("opendiscord:checkbox-select-question",{cliDisplayKeyInParentArray:"name",cliDisplayAdditionalKeysInParentArray:["id","type"],children:[ + {key:"id",checker:new api.ODCheckerCustomStructure_UniqueId("opendiscord:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-รฉรจรงร รชรขรดรปรฎ]+$/,minLength:3,maxLength:40,cliDisplayName:"Id",cliDisplayDescription:"The id of this question. Used in ticket options."})}, + {key:"name",checker:new api.ODCheckerStringStructure("opendiscord:question-name",{minLength:3,maxLength:45,cliDisplayName:"Name",cliDisplayDescription:"The name of this question."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:question-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this question."})}, + {key:"required",checker:new api.ODCheckerBooleanStructure("opendiscord:question-required",{cliDisplayName:"Required",cliDisplayDescription:"Is this question required? If not, it can be left empty."})}, + + {key:"limits",checker:new api.ODCheckerEnabledObjectStructure("opendiscord:amount",{property:"enabled",enabledValue:true,checker:new api.ODCheckerObjectStructure("opendiscord:amount",{children:[ + {key:"enabled",checker:new api.ODCheckerBooleanStructure("opendiscord:amount-enabled",{cliDisplayName:"Enabled",cliDisplayDescription:"Enable/disable checking the min/max amount of required checkboxes."})}, + {key:"min",checker:new api.ODCheckerNumberStructure("opendiscord:amount-min",{min:0,max:10,floatAllowed:false,cliDisplayName:"Min Amount",cliDisplayDescription:"The minimum amount of checkboxes required."})}, + {key:"max",checker:new api.ODCheckerNumberStructure("opendiscord:amount-max",{min:1,max:10,floatAllowed:false,cliInitDefaultValue:10,cliDisplayName:"Max Amount",cliDisplayDescription:"The maximum amount of checkboxes allowed."})}, + ],cliDisplayName:"Checkbox Limits",cliDisplayDescription:"Verify the minimum or maximum amount of checkboxes required."}),cliDisplayName:"Checkbox Limits",cliDisplayDescription:"Verify the minimum or maximum amount of checkboxes required."})}, + + {key:"choices",checker:new api.ODCheckerArrayStructure("opendiscord:choices",{allowedTypes:["object"],minLength:1,maxLength:10,propertyChecker:new api.ODCheckerObjectStructure("opendiscord:choice",{children:[ + {key:"title",checker:new api.ODCheckerStringStructure("opendiscord:choice-title",{minLength:1,maxLength:100,cliDisplayName:"Title",cliDisplayDescription:"The title of this choice."})}, + {key:"description",checker:new api.ODCheckerStringStructure("opendiscord:choice-description",{maxLength:100,cliDisplayName:"Description",cliDisplayDescription:"The description of this choice."})}, + {key:"selectedByDefault",checker:new api.ODCheckerBooleanStructure("opendiscord:choice-default",{cliDisplayName:"Selected By Default",cliDisplayDescription:"Should this choice be selected by default?"})} + ],cliDisplayName:"Choice",cliDisplayDescription:"A choice for this checkbox select question."}),cliDisplayName:"Choices",cliDisplayPropertyName:"choice",cliDisplayDescription:"Manage all available choices of this checkbox select question."})} + ],cliDisplayName:"Checkbox Select Question",cliDisplayDescription:"Manage, customise and configure the checkbox select question to your preference."})}, + +],cliDisplayName:"Question",cliDisplayDescription:"Manage a question of one of the 6 types: short, paragraph, text-display, dropdown, radio-select, checkbox-select."}),cliDisplayName:"Questions",cliDisplayDescription:"A list of all questions in the bot. Here you can add, modify & remove existing questions or customise them to your preference."}) export const defaultTranscriptsStructure = new api.ODCheckerObjectStructure("opendiscord:transcripts",{children:[ //GENERAL diff --git a/src/data/framework/codeLoader.ts b/src/data/framework/codeLoader.ts index 8a0f32f..af57c14 100644 --- a/src/data/framework/codeLoader.ts +++ b/src/data/framework/codeLoader.ts @@ -30,7 +30,7 @@ export async function loadCommandErrorHandlingCode(){ error.msg.channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-option-invalid").build("text",{guild:error.msg.guild,channel:error.msg.channel,user:error.msg.author,error})).message) }else if (error.type == "missing_option"){ error.msg.channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-option-missing").build("text",{guild:error.msg.guild,channel:error.msg.channel,user:error.msg.author,error})).message) - }else if (error.type == "unknown_command" && generalConfig.data.system.sendErrorOnUnknownCommand){ + }else if (error.type == "unknown_command" && generalConfig.data.ticketSystem.sendErrorOnUnknownCommand){ error.msg.channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-unknown-command").build("text",{guild:error.msg.guild,channel:error.msg.channel,user:error.msg.author,error})).message) } }) @@ -459,7 +459,7 @@ const loadAutoCode = () => { if (lastMessage){ //ticket has last message const disableOnClaim = ticket.option.get("opendiscord:autodelete-disable-claim").value && ticket.get("opendiscord:claimed").value - const disableWhenNotClosed = generalConfig.data.system.autodeleteRequiresClosedTicket && !ticket.get("opendiscord:closed").value + const disableWhenNotClosed = generalConfig.data.ticketSystem.autodeleteRequiresClosedTicket && !ticket.get("opendiscord:closed").value const enabled = (disableOnClaim || disableWhenNotClosed) ? false : ticket.get("opendiscord:autodelete-enabled").value const days = ticket.get("opendiscord:autodelete-days").value @@ -490,7 +490,7 @@ const loadAutoCode = () => { if (!channel) return //ticket has been created by this user const disableOnClaim = ticket.option.get("opendiscord:autodelete-disable-claim").value && ticket.get("opendiscord:claimed").value - const disableWhenNotClosed = generalConfig.data.system.autodeleteRequiresClosedTicket && !ticket.get("opendiscord:closed").value + const disableWhenNotClosed = generalConfig.data.ticketSystem.autodeleteRequiresClosedTicket && !ticket.get("opendiscord:closed").value const enabled = (disableOnClaim || disableWhenNotClosed || !ticket.get("opendiscord:autodelete-enabled").value) ? false : ticket.option.get("opendiscord:autodelete-enable-leave") if (enabled){ diff --git a/src/data/framework/commandLoader.ts b/src/data/framework/commandLoader.ts index d6df28d..ec97ed0 100644 --- a/src/data/framework/commandLoader.ts +++ b/src/data/framework/commandLoader.ts @@ -14,8 +14,8 @@ export async function loadAllSlashCommands(){ if (!generalConfig.data.slashCommands) return const allowedCommands: string[] = [] - for (const key in generalConfig.data.system.permissions){ - if (generalConfig.data.system.permissions[key] != "none") allowedCommands.push(key) + for (const key in generalConfig.data.permissions){ + if (generalConfig.data.permissions[key] != "none") allowedCommands.push(key) } //HELP @@ -87,7 +87,7 @@ export async function loadAllSlashCommands(){ })) //DELETE - if (allowedCommands.includes("delete") && generalConfig.data.system.enableDeleteWithoutTranscript) commands.add(new api.ODSlashCommand("opendiscord:delete",{ + if (allowedCommands.includes("delete") && generalConfig.data.ticketSystem.enableDeleteWithoutTranscript) commands.add(new api.ODSlashCommand("opendiscord:delete",{ type:act.ChatInput, name:"delete", description:lang.getTranslation("commands.delete"), @@ -654,8 +654,8 @@ export async function loadAllTextCommands(){ }) const allowedCommands: string[] = [] - for (const key in generalConfig.data.system.permissions){ - if (generalConfig.data.system.permissions[key] != "none") allowedCommands.push(key) + for (const key in generalConfig.data.permissions){ + if (generalConfig.data.permissions[key] != "none") allowedCommands.push(key) } //HELP diff --git a/src/data/framework/configLoader.ts b/src/data/framework/configLoader.ts index a977e24..d845586 100644 --- a/src/data/framework/configLoader.ts +++ b/src/data/framework/configLoader.ts @@ -5,121 +5,63 @@ export async function loadAllConfigs(){ const devconfigFlag = opendiscord.flags.get("opendiscord:dev-config") const isDevconfig = devconfigFlag ? devconfigFlag.value : false - opendiscord.configs.add(new api.ODJsonConfig("opendiscord:general","general.json",(isDevconfig) ? "./devconfig/" : "./config/",defaultGeneralFormatter)) - opendiscord.configs.add(new api.ODJsonConfig("opendiscord:questions","questions.json",(isDevconfig) ? "./devconfig/" : "./config/",defaultQuestionsFormatter)) - opendiscord.configs.add(new api.ODJsonConfig("opendiscord:options","options.json",(isDevconfig) ? "./devconfig/" : "./config/",defaultOptionsFormatter)) - opendiscord.configs.add(new api.ODJsonConfig("opendiscord:panels","panels.json",(isDevconfig) ? "./devconfig/" : "./config/",defaultPanelsFormatter)) - opendiscord.configs.add(new api.ODJsonConfig("opendiscord:transcripts","transcripts.json",(isDevconfig) ? "./devconfig/" : "./config/",defaultTranscriptsFormatter)) + opendiscord.configs.add(new api.ODJsonCommentsConfig("opendiscord:general","general.jsonc",(isDevconfig) ? "./devconfig/" : "./config/",defaultGeneralFormatter)) + opendiscord.configs.add(new api.ODJsonCommentsConfig("opendiscord:questions","questions.jsonc",(isDevconfig) ? "./devconfig/" : "./config/",defaultQuestionsFormatter)) + opendiscord.configs.add(new api.ODJsonCommentsConfig("opendiscord:options","options.jsonc",(isDevconfig) ? "./devconfig/" : "./config/",defaultOptionsFormatter)) + opendiscord.configs.add(new api.ODJsonCommentsConfig("opendiscord:panels","panels.jsonc",(isDevconfig) ? "./devconfig/" : "./config/",defaultPanelsFormatter)) + opendiscord.configs.add(new api.ODJsonCommentsConfig("opendiscord:transcripts","transcripts.jsonc",(isDevconfig) ? "./devconfig/" : "./config/",defaultTranscriptsFormatter)) } //FORMATTERS -export const defaultGeneralFormatter = new fjs.ObjectFormatter(null,true,[ - new fjs.ObjectFormatter("_INFO",true,[ - new fjs.PropertyFormatter("support"), - new fjs.PropertyFormatter("discord"), - new fjs.PropertyFormatter("version"), - ]), +export const defaultGeneralFormatter = new fjs.TopLevelCommentFormatter(new fjs.MultiCommentFormatter([ + "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", + ].join("\n")),new fjs.ObjectFormatter(null,true,[ + new fjs.PropertyFormatter("_CONFIG_VERSION"), new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Load the bot token from .env or the \"token\" field below. Leave \"token\" empty if using \"tokenFromENV\"."), new fjs.PropertyFormatter("token"), new fjs.PropertyFormatter("tokenFromENV"), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("mainColor"), - new fjs.PropertyFormatter("language"), - new fjs.PropertyFormatter("prefix"), + new fjs.PropertyFormatter("mainColor",new fjs.SingleCommentFormatter("Hex color used in most embeds")), + new fjs.PropertyFormatter("language",new fjs.SingleCommentFormatter("Visit README.md for list")), + new fjs.PropertyFormatter("prefix",new fjs.SingleCommentFormatter("Prefix used in text commands")), new fjs.PropertyFormatter("serverId"), - new fjs.ArrayFormatter("globalAdmins",false,new fjs.PropertyFormatter(null)), + new fjs.ArrayFormatter("globalAdmins",false,new fjs.PropertyFormatter(null),undefined,undefined,new fjs.SingleCommentFormatter("Have access to all commands")), new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Enable/disable text or slash commands."), new fjs.PropertyFormatter("slashCommands"), new fjs.PropertyFormatter("textCommands"), new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Configure the status of the bot."), new fjs.ObjectFormatter("status",true,[ new fjs.PropertyFormatter("enabled"), - new fjs.PropertyFormatter("type"), - new fjs.PropertyFormatter("mode"), + new fjs.PropertyFormatter("type",new fjs.SingleCommentFormatter("Choices: listening, watching, playing, custom")), + new fjs.PropertyFormatter("mode",new fjs.SingleCommentFormatter("Choices: online, invisible, idle, dnd")), new fjs.PropertyFormatter("text"), - new fjs.PropertyFormatter("state"), + new fjs.PropertyFormatter("state",new fjs.SingleCommentFormatter("Additional text (Leave empty to disable)")), ]), new fjs.TextFormatter(""), - new fjs.ObjectFormatter("system",true,[ - new fjs.PropertyFormatter("preferSlashOverText"), - new fjs.PropertyFormatter("sendErrorOnUnknownCommand"), - new fjs.PropertyFormatter("questionFieldsInCodeBlock"), - new fjs.PropertyFormatter("displayFieldsWithQuestions"), - new fjs.PropertyFormatter("showGlobalAdminsInPanelRoles"), - new fjs.PropertyFormatter("disableVerifyBars"), - new fjs.PropertyFormatter("useRedErrorEmbeds"), - new fjs.PropertyFormatter("alwaysShowReason"), - new fjs.PropertyFormatter("emojiStyle"), - new fjs.PropertyFormatter("pinEmoji"), - new fjs.TextFormatter(""), - new fjs.PropertyFormatter("replyOnTicketCreation"), - new fjs.PropertyFormatter("replyOnReactionRole"), - new fjs.PropertyFormatter("askPriorityOnTicketCreation"), - new fjs.PropertyFormatter("removeParticipantsOnClose"), - new fjs.PropertyFormatter("disableAutocloseAfterReopen"), - new fjs.PropertyFormatter("autodeleteRequiresClosedTicket"), - new fjs.PropertyFormatter("adminOnlyDeleteWithoutTranscript"), - new fjs.PropertyFormatter("allowCloseBeforeMessage"), - new fjs.PropertyFormatter("allowCloseBeforeAdminMessage"), - new fjs.PropertyFormatter("useTranslatedConfigChecker"), - new fjs.PropertyFormatter("pinFirstTicketMessage"), - new fjs.TextFormatter(""), - new fjs.PropertyFormatter("enableTicketClaimButtons"), - new fjs.PropertyFormatter("enableTicketCloseButtons"), - new fjs.PropertyFormatter("enableTicketPinButtons"), - new fjs.PropertyFormatter("enableTicketDeleteButtons"), - new fjs.PropertyFormatter("enableTicketActionWithReason"), - new fjs.PropertyFormatter("enableDeleteWithoutTranscript"), - new fjs.TextFormatter(""), - new fjs.ObjectFormatter("logs",true,[ - new fjs.PropertyFormatter("enabled"), - new fjs.PropertyFormatter("channel"), - ]), - new fjs.TextFormatter(""), - new fjs.ObjectFormatter("limits",true,[ - new fjs.PropertyFormatter("enabled"), - new fjs.PropertyFormatter("globalMaximum"), - new fjs.PropertyFormatter("userMaximum"), - ]), - new fjs.TextFormatter(""), - new fjs.ObjectFormatter("channelTopic",true,[ - new fjs.PropertyFormatter("showOptionName"), - new fjs.PropertyFormatter("showOptionDescription"), - new fjs.PropertyFormatter("showOptionTopic"), - new fjs.PropertyFormatter("showPriority"), - new fjs.PropertyFormatter("showClosed"), - new fjs.PropertyFormatter("showClaimed"), - new fjs.PropertyFormatter("showPinned"), - new fjs.PropertyFormatter("showCreator"), - new fjs.PropertyFormatter("showParticipants"), - ]), - new fjs.TextFormatter(""), - new fjs.ObjectFormatter("permissions",true,[ - new fjs.PropertyFormatter("help"), - new fjs.PropertyFormatter("panel"), - new fjs.PropertyFormatter("ticket"), - new fjs.PropertyFormatter("close"), - new fjs.PropertyFormatter("delete"), - new fjs.PropertyFormatter("reopen"), - new fjs.PropertyFormatter("claim"), - new fjs.PropertyFormatter("unclaim"), - new fjs.PropertyFormatter("pin"), - new fjs.PropertyFormatter("unpin"), - new fjs.PropertyFormatter("move"), - new fjs.PropertyFormatter("rename"), - new fjs.PropertyFormatter("add"), - new fjs.PropertyFormatter("remove"), - new fjs.PropertyFormatter("blacklist"), - new fjs.PropertyFormatter("stats"), - new fjs.PropertyFormatter("clear"), - new fjs.PropertyFormatter("autoclose"), - new fjs.PropertyFormatter("autodelete"), - new fjs.PropertyFormatter("transfer"), - new fjs.PropertyFormatter("topic"), - new fjs.PropertyFormatter("priority"), - ]), - new fjs.TextFormatter(""), - new fjs.ObjectFormatter("messages",true,[ + new fjs.MultiCommentFormatter("Send ticket logs to a channel or in DM of the ticket creator."), + new fjs.ObjectFormatter("logs",true,[ + new fjs.PropertyFormatter("enabled"), + new fjs.PropertyFormatter("channel"), + new fjs.ObjectFormatter("logMessages",true,[ new fjs.DefaultFormatter("creation",false), new fjs.DefaultFormatter("closing",false), new fjs.DefaultFormatter("deleting",false), @@ -137,80 +79,267 @@ export const defaultGeneralFormatter = new fjs.ObjectFormatter(null,true,[ new fjs.DefaultFormatter("reactionRole",false) ]), ]), -]) + new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("A large collection of settings for the ticket system."), + new fjs.ObjectFormatter("ticketSystem",true,[ + new fjs.PropertyFormatter("preferSlashOverText",new fjs.SingleCommentFormatter("Show slashcmds in help menu's")), + new fjs.PropertyFormatter("sendErrorOnUnknownCommand",new fjs.SingleCommentFormatter("Send error when command not found")), + new fjs.PropertyFormatter("questionFieldsInCodeBlock",new fjs.SingleCommentFormatter("Put question answers in code blocks")), + new fjs.PropertyFormatter("displayFieldsWithQuestions",new fjs.SingleCommentFormatter("Display embed fields together with question answers")), + new fjs.PropertyFormatter("showGlobalAdminsInPanelRoles",new fjs.SingleCommentFormatter("Include \"globalAdmins\" in panel admin lists")), + new fjs.PropertyFormatter("disableVerifyBars",new fjs.SingleCommentFormatter("Disable the (โŒ/โœ…) buttons")), + new fjs.PropertyFormatter("useRedErrorEmbeds",new fjs.SingleCommentFormatter("Make errors embeds always red")), + new fjs.PropertyFormatter("alwaysShowReason",new fjs.SingleCommentFormatter("Show reason even if none is provided")), + new fjs.PropertyFormatter("emojiStyle",new fjs.SingleCommentFormatter("The style of emoji's in embeds. Choices: before, after, double, disabled")), + new fjs.PropertyFormatter("pinEmoji",new fjs.SingleCommentFormatter("Channel emoji of pinned tickets (Leave empty to disable)")), + new fjs.PropertyFormatter("closeEmoji",new fjs.SingleCommentFormatter("Channel emoji of closed tickets (Leave empty to disable)")), + new fjs.TextFormatter(""), + new fjs.PropertyFormatter("replyOnTicketCreation",new fjs.SingleCommentFormatter("Reply with a msg when a ticket is created")), + new fjs.PropertyFormatter("replyOnReactionRole",new fjs.SingleCommentFormatter("Reply with a msg when a reaction role is used")), + new fjs.PropertyFormatter("askPriorityOnTicketCreation",new fjs.SingleCommentFormatter("Show a dropdown to select priority")), + new fjs.PropertyFormatter("removeParticipantsOnClose",new fjs.SingleCommentFormatter("Remove non-admins when ticket is closed")), + new fjs.PropertyFormatter("disableAutocloseAfterReopen",new fjs.SingleCommentFormatter("Disable autoclose after ticket got reopened")), + new fjs.PropertyFormatter("autodeleteRequiresClosedTicket",new fjs.SingleCommentFormatter("A ticket must be closed before autodelete works")), + new fjs.PropertyFormatter("adminOnlyDeleteWithoutTranscript",new fjs.SingleCommentFormatter("Only allow \"globalAdmins\" to delete a ticket without transcript")), + new fjs.PropertyFormatter("allowCloseBeforeMessage",new fjs.SingleCommentFormatter("Allow closing before a message is sent")), + new fjs.PropertyFormatter("allowCloseBeforeAdminMessage",new fjs.SingleCommentFormatter("Allow closing before an admin has sent a message")), + new fjs.PropertyFormatter("useTranslatedConfigChecker",new fjs.SingleCommentFormatter("Translate config errors in the console")), + new fjs.PropertyFormatter("pinFirstTicketMessage",new fjs.SingleCommentFormatter("Pin the ticket message to the channel")), + new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Enable/disable certain buttons & features of the bot."), + new fjs.PropertyFormatter("enableTicketClaimButtons"), + new fjs.PropertyFormatter("enableTicketCloseButtons"), + new fjs.PropertyFormatter("enableTicketPinButtons"), + new fjs.PropertyFormatter("enableTicketDeleteButtons"), + new fjs.PropertyFormatter("enableTicketActionWithReason"), + new fjs.PropertyFormatter("enableDeleteWithoutTranscript",new fjs.SingleCommentFormatter("Allow deleting tickets without transcript")), + new fjs.PropertyFormatter("enableCreateTicketForOtherUser",new fjs.SingleCommentFormatter("Allow creating tickets for other users")), + new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Set the maximum amount of simultaneous tickets."), + new fjs.ObjectFormatter("limits",true,[ + new fjs.PropertyFormatter("enabled"), + new fjs.PropertyFormatter("globalMaximum"), + new fjs.PropertyFormatter("userMaximum"), + ]), + new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Choose which data is shown in the channel topic."), + new fjs.ObjectFormatter("channelTopic",true,[ + new fjs.PropertyFormatter("showOptionName"), + new fjs.PropertyFormatter("showOptionDescription"), + new fjs.PropertyFormatter("showOptionTopic"), + new fjs.PropertyFormatter("showPriority"), + new fjs.PropertyFormatter("showClosed"), + new fjs.PropertyFormatter("showClaimed"), + new fjs.PropertyFormatter("showPinned"), + new fjs.PropertyFormatter("showCreator"), + new fjs.PropertyFormatter("showParticipants"), + ]), + new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Move closed tickets to a separate category."), + new fjs.ObjectFormatter("closedCategory",true,[ + new fjs.PropertyFormatter("enabled"), + new fjs.PropertyFormatter("categoryId") + ]), + new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Create tickets in a backup category when the original category exceeds 50 channels."), + new fjs.ObjectFormatter("backupCategory",true,[ + new fjs.PropertyFormatter("enabled"), + new fjs.PropertyFormatter("categoryId") + ]), + new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Move claimed tickets to a matching category of the user that claimed the ticket. Set to empty list [] to disable."), + new fjs.ArrayFormatter("claimedCategories",true,new fjs.ObjectFormatter(null,false,[ + new fjs.PropertyFormatter("user"), + new fjs.PropertyFormatter("category"), + ])), + ]), + new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter([ + "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", + ].join("\n")), + new fjs.ObjectFormatter("permissions",true,[ + new fjs.PropertyFormatter("help"), + new fjs.PropertyFormatter("panel"), + new fjs.PropertyFormatter("ticket"), + new fjs.PropertyFormatter("close"), + new fjs.PropertyFormatter("delete"), + new fjs.PropertyFormatter("reopen"), + new fjs.PropertyFormatter("claim"), + new fjs.PropertyFormatter("unclaim"), + new fjs.PropertyFormatter("pin"), + new fjs.PropertyFormatter("unpin"), + new fjs.PropertyFormatter("move"), + new fjs.PropertyFormatter("rename"), + new fjs.PropertyFormatter("add"), + new fjs.PropertyFormatter("remove"), + new fjs.PropertyFormatter("blacklist"), + new fjs.PropertyFormatter("stats"), + new fjs.PropertyFormatter("clear"), + new fjs.PropertyFormatter("autoclose"), + new fjs.PropertyFormatter("autodelete"), + new fjs.PropertyFormatter("transfer"), + new fjs.PropertyFormatter("topic"), + new fjs.PropertyFormatter("priority"), + new fjs.PropertyFormatter("transcripts"), + ]), +])) -export const defaultQuestionsFormatter = new fjs.ArrayFormatter(null,true,new fjs.ObjectSwitchFormatter(null,[ +export const defaultQuestionsFormatter = new fjs.TopLevelCommentFormatter(new fjs.MultiCommentFormatter([ + "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." + ].join("\n")),new fjs.ArrayFormatter(null,true,new fjs.ObjectSwitchFormatter(null,[ {key:"type",value:"short",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A short text input modal question."), new fjs.PropertyFormatter("id"), new fjs.PropertyFormatter("name"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), new fjs.PropertyFormatter("type"), - new fjs.TextFormatter(""), new fjs.PropertyFormatter("required"), + new fjs.TextFormatter(""), new fjs.PropertyFormatter("placeholder"), new fjs.ObjectFormatter("length",true,[ + new fjs.MultiCommentFormatter("Configure length limits for the answer."), new fjs.PropertyFormatter("enabled"), new fjs.PropertyFormatter("min"), new fjs.PropertyFormatter("max"), ]), ])}, {key:"type",value:"paragraph",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A paragraph text input modal question."), new fjs.PropertyFormatter("id"), new fjs.PropertyFormatter("name"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), new fjs.PropertyFormatter("type"), - new fjs.TextFormatter(""), new fjs.PropertyFormatter("required"), + new fjs.TextFormatter(""), new fjs.PropertyFormatter("placeholder"), new fjs.ObjectFormatter("length",true,[ + new fjs.MultiCommentFormatter("Configure length limits for the answer."), new fjs.PropertyFormatter("enabled"), new fjs.PropertyFormatter("min"), new fjs.PropertyFormatter("max"), ]), - ])} -])) - - -export const defaultOptionsFormatter = new fjs.ArrayFormatter(null,true,new fjs.ObjectSwitchFormatter(null,[ - {key:"type",value:"ticket",formatter:new fjs.ObjectFormatter(null,true,[ + ])}, + {key:"type",value:"text-display",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("Show text in a modal to provide extra details or explain questions."), + new fjs.PropertyFormatter("id"), + new fjs.PropertyFormatter("type"), + new fjs.TextFormatter(""), + new fjs.PropertyFormatter("textContents"), + ])}, + {key:"type",value:"dropdown",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A dropdown menu input modal question with up to 25 choices. \"emoji\" & \"description\" fields are optional."), new fjs.PropertyFormatter("id"), new fjs.PropertyFormatter("name"), - new fjs.PropertyFormatter("description"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("type"), + new fjs.PropertyFormatter("required"), + new fjs.TextFormatter(""), + new fjs.PropertyFormatter("placeholder"), + new fjs.ArrayFormatter("choices",true,new fjs.ObjectFormatter(null,false,[ + new fjs.PropertyFormatter("title"), + new fjs.PropertyFormatter("description"), + new fjs.PropertyFormatter("emoji"), + ])), + ])}, + {key:"type",value:"radio-select",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A radio select input modal question with up to 10 choices."), + new fjs.PropertyFormatter("id"), + new fjs.PropertyFormatter("name"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("type"), + new fjs.PropertyFormatter("required"), + new fjs.TextFormatter(""), + new fjs.ArrayFormatter("choices",true,new fjs.ObjectFormatter(null,false,[ + new fjs.PropertyFormatter("title"), + new fjs.PropertyFormatter("description"), + new fjs.PropertyFormatter("selectedByDefault"), + ])), + ])}, + {key:"type",value:"checkbox-select",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A checkbox select input modal question with up to 10 choices."), + new fjs.PropertyFormatter("id"), + new fjs.PropertyFormatter("name"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("type"), + new fjs.PropertyFormatter("required"), + new fjs.TextFormatter(""), + new fjs.ObjectFormatter("limits",true,[ + new fjs.MultiCommentFormatter("Configure checkbox amount limits for the answer."), + new fjs.PropertyFormatter("enabled"), + new fjs.PropertyFormatter("min"), + new fjs.PropertyFormatter("max"), + ]), + new fjs.ArrayFormatter("choices",true,new fjs.ObjectFormatter(null,false,[ + new fjs.PropertyFormatter("title"), + new fjs.PropertyFormatter("description"), + new fjs.PropertyFormatter("selectedByDefault"), + ])), + ])}, +]))) + + +export const defaultOptionsFormatter = new fjs.TopLevelCommentFormatter(new fjs.MultiCommentFormatter([ + "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." + ].join("\n")),new fjs.ArrayFormatter(null,true,new fjs.ObjectSwitchFormatter(null,[ + {key:"type",value:"ticket",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A ticket option creates a button to open a ticket."), + new fjs.PropertyFormatter("id"), + new fjs.PropertyFormatter("name"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), new fjs.PropertyFormatter("type"), new fjs.TextFormatter(""), new fjs.ObjectFormatter("button",true,[ + new fjs.MultiCommentFormatter("Configure the button style of this option. At least one of \"emoji\" or \"label\" must be provided."), new fjs.PropertyFormatter("emoji"), new fjs.PropertyFormatter("label"), - new fjs.PropertyFormatter("color"), + new fjs.PropertyFormatter("color",new fjs.SingleCommentFormatter("Choices: gray, red, green, blue")), ]), new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Add up to 5 modal questions IDs from (config/questions.jsonc)."), + new fjs.ArrayFormatter("questions",false,new fjs.PropertyFormatter(null)), + new fjs.TextFormatter(""), new fjs.ArrayFormatter("ticketAdmins",false,new fjs.PropertyFormatter(null)), new fjs.ArrayFormatter("readonlyAdmins",false,new fjs.PropertyFormatter(null)), new fjs.PropertyFormatter("allowCreationByBlacklistedUsers"), - new fjs.ArrayFormatter("questions",false,new fjs.PropertyFormatter(null)), new fjs.TextFormatter(""), new fjs.ObjectFormatter("channel",true,[ + new fjs.MultiCommentFormatter("Configure the name, topic and category of the ticket option."), new fjs.PropertyFormatter("prefix"), - new fjs.PropertyFormatter("suffix"), - new fjs.PropertyFormatter("category"), - new fjs.PropertyFormatter("backupCategory"), - new fjs.PropertyFormatter("closedCategory"), - new fjs.ArrayFormatter("claimedCategory",true,new fjs.ObjectFormatter(null,false,[ - new fjs.PropertyFormatter("user"), - new fjs.PropertyFormatter("category"), - ])), - new fjs.PropertyFormatter("topic"), + new fjs.PropertyFormatter("suffix",new fjs.SingleCommentFormatter("Choices: user-name, user-id, random-number, random-hex, counter-dynamic, counter-fixed")), + new fjs.PropertyFormatter("category",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("topic",new fjs.SingleCommentFormatter("Leave empty to disable")), ]), new fjs.TextFormatter(""), new fjs.ObjectFormatter("dmMessage",true,[ + new fjs.MultiCommentFormatter("Send a customisable message in DM when creating a ticket."), new fjs.PropertyFormatter("enabled"), - new fjs.PropertyFormatter("text"), + new fjs.PropertyFormatter("text",new fjs.SingleCommentFormatter("Leave empty to disable")), new fjs.ObjectFormatter("embed",true,[ new fjs.PropertyFormatter("enabled"), - new fjs.PropertyFormatter("title"), - new fjs.PropertyFormatter("description"), - new fjs.PropertyFormatter("customColor"), + new fjs.PropertyFormatter("title",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("customColor",new fjs.SingleCommentFormatter("Leave empty to use default color")), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("image"), - new fjs.PropertyFormatter("thumbnail"), + new fjs.PropertyFormatter("image",new fjs.SingleCommentFormatter("Image URL. Leave empty to disable")), + new fjs.PropertyFormatter("thumbnail",new fjs.SingleCommentFormatter("Image URL. Leave empty to disable")), + new fjs.MultiCommentFormatter("Embed fields. Set to empty list [] to disable."), new fjs.ArrayFormatter("fields",true,new fjs.ObjectFormatter(null,false,[ new fjs.PropertyFormatter("name"), new fjs.PropertyFormatter("value"), @@ -220,16 +349,18 @@ export const defaultOptionsFormatter = new fjs.ArrayFormatter(null,true,new fjs. ]), ]), new fjs.ObjectFormatter("ticketMessage",true,[ + new fjs.MultiCommentFormatter("Send a customisable message in the ticket with close, claim, delete, ... buttons."), new fjs.PropertyFormatter("enabled"), - new fjs.PropertyFormatter("text"), + new fjs.PropertyFormatter("text",new fjs.SingleCommentFormatter("Leave empty to disable")), new fjs.ObjectFormatter("embed",true,[ new fjs.PropertyFormatter("enabled"), - new fjs.PropertyFormatter("title"), - new fjs.PropertyFormatter("description"), - new fjs.PropertyFormatter("customColor"), + new fjs.PropertyFormatter("title",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("customColor",new fjs.SingleCommentFormatter("Leave empty to use default color")), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("image"), - new fjs.PropertyFormatter("thumbnail"), + new fjs.PropertyFormatter("image",new fjs.SingleCommentFormatter("Image URL. Leave empty to disable")), + new fjs.PropertyFormatter("thumbnail",new fjs.SingleCommentFormatter("Image URL. Leave empty to disable")), + new fjs.MultiCommentFormatter("Embed fields. Set to empty list [] to disable."), new fjs.ArrayFormatter("fields",true,new fjs.ObjectFormatter(null,false,[ new fjs.PropertyFormatter("name"), new fjs.PropertyFormatter("value"), @@ -238,44 +369,52 @@ export const defaultOptionsFormatter = new fjs.ArrayFormatter(null,true,new fjs. new fjs.PropertyFormatter("timestamp"), ]), new fjs.ObjectFormatter("ping",true,[ + new fjs.MultiCommentFormatter("Customise the user & role mentions of this ticket message."), new fjs.PropertyFormatter("@here"), new fjs.PropertyFormatter("@everyone"), - new fjs.ArrayFormatter("custom",true,new fjs.PropertyFormatter(null)), + new fjs.ArrayFormatter("custom",false,new fjs.PropertyFormatter(null)), ]), ]), new fjs.ObjectFormatter("autoclose",true,[ + new fjs.MultiCommentFormatter("Autoclose this ticket after a period of inactivity or when the creator leaves the server."), new fjs.PropertyFormatter("enableInactiveHours"), new fjs.PropertyFormatter("inactiveHours"), new fjs.PropertyFormatter("enableUserLeave"), new fjs.PropertyFormatter("disableOnClaim"), ]), new fjs.ObjectFormatter("autodelete",true,[ + new fjs.MultiCommentFormatter("Autodelete this ticket after a period of inactivity or when the creator leaves the server."), new fjs.PropertyFormatter("enableInactiveDays"), new fjs.PropertyFormatter("inactiveDays"), new fjs.PropertyFormatter("enableUserLeave"), new fjs.PropertyFormatter("disableOnClaim"), ]), new fjs.ObjectFormatter("cooldown",true,[ + new fjs.MultiCommentFormatter("Users must wait a certain period before being able to create another ticket of this type."), new fjs.PropertyFormatter("enabled"), new fjs.PropertyFormatter("cooldownMinutes"), ]), new fjs.ObjectFormatter("limits",true,[ + new fjs.MultiCommentFormatter("Set the maximum amount of simultaneous tickets of this option."), new fjs.PropertyFormatter("enabled"), new fjs.PropertyFormatter("globalMaximum"), new fjs.PropertyFormatter("userMaximum"), ]), new fjs.ObjectFormatter("slowMode",true,[ + new fjs.MultiCommentFormatter("Enable slow-mode in the ticket channel."), new fjs.PropertyFormatter("enabled"), new fjs.PropertyFormatter("slowModeSeconds"), ]), ])}, {key:"type",value:"website",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A website option creates a button with a URL to an external website."), new fjs.PropertyFormatter("id"), new fjs.PropertyFormatter("name"), - new fjs.PropertyFormatter("description"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), new fjs.PropertyFormatter("type"), new fjs.TextFormatter(""), new fjs.ObjectFormatter("button",true,[ + new fjs.MultiCommentFormatter("Configure the button style of this option. At least one of \"emoji\" or \"label\" must be provided."), new fjs.PropertyFormatter("emoji"), new fjs.PropertyFormatter("label"), ]), @@ -283,43 +422,75 @@ export const defaultOptionsFormatter = new fjs.ArrayFormatter(null,true,new fjs. new fjs.PropertyFormatter("url"), ])}, {key:"type",value:"role",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A reaction-role option creates a button for members to choose roles."), new fjs.PropertyFormatter("id"), new fjs.PropertyFormatter("name"), - new fjs.PropertyFormatter("description"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), new fjs.PropertyFormatter("type"), new fjs.TextFormatter(""), new fjs.ObjectFormatter("button",true,[ + new fjs.MultiCommentFormatter("Configure the button style of this option. At least one of \"emoji\" or \"label\" must be provided."), new fjs.PropertyFormatter("emoji"), new fjs.PropertyFormatter("label"), - new fjs.PropertyFormatter("color"), + new fjs.PropertyFormatter("color",new fjs.SingleCommentFormatter("Choices: gray, red, green, blue")), ]), new fjs.TextFormatter(""), new fjs.ArrayFormatter("roles",false,new fjs.PropertyFormatter(null)), - new fjs.PropertyFormatter("mode"), - new fjs.ArrayFormatter("removeRolesOnAdd",false,new fjs.PropertyFormatter(null)), - new fjs.PropertyFormatter("addOnMemberJoin"), + new fjs.PropertyFormatter("mode",new fjs.SingleCommentFormatter("What to do with the roles. Choices: add&remove, add, remove")), + new fjs.ArrayFormatter("removeRolesOnAdd",false,new fjs.PropertyFormatter(null),undefined,undefined,new fjs.SingleCommentFormatter("Remove these old roles when new roles are added.")), + new fjs.PropertyFormatter("addOnMemberJoin",new fjs.SingleCommentFormatter("Add these roles automatically when joining the server.")), + ])}, + {key:"type",value:"sub-panel",formatter:new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A sub-panel option creates a button which sends another panel for additional options."), + new fjs.PropertyFormatter("id"), + new fjs.PropertyFormatter("name"), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("type"), + new fjs.TextFormatter(""), + new fjs.ObjectFormatter("button",true,[ + new fjs.MultiCommentFormatter("Configure the button style of this option. At least one of \"emoji\" or \"label\" must be provided."), + new fjs.PropertyFormatter("emoji"), + new fjs.PropertyFormatter("label"), + new fjs.PropertyFormatter("color",new fjs.SingleCommentFormatter("Choices: gray, red, green, blue")), + ]), + new fjs.TextFormatter(""), + new fjs.PropertyFormatter("subPanelId",new fjs.SingleCommentFormatter("Choose a panel ID from (config/panels.jsonc)")), ])} -])) +]))) -export const defaultPanelsFormatter = new fjs.ArrayFormatter(null,true,new fjs.ObjectFormatter(null,true,[ +export const defaultPanelsFormatter = new fjs.TopLevelCommentFormatter(new fjs.MultiCommentFormatter([ + "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 ", + "", + "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." + ].join("\n")),new fjs.ArrayFormatter(null,true,new fjs.ObjectFormatter(null,true,[ + new fjs.MultiCommentFormatter("A panel is creates a message with up to 25 options as buttons or dropdown."), new fjs.PropertyFormatter("id"), new fjs.PropertyFormatter("name"), new fjs.PropertyFormatter("dropdown"), + new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Add up to 5 option IDs from (config/options.jsonc)."), new fjs.ArrayFormatter("options",false,new fjs.PropertyFormatter(null)), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("text"), + new fjs.PropertyFormatter("text",new fjs.SingleCommentFormatter("Leave empty to disable")), new fjs.ObjectFormatter("embed",true,[ new fjs.PropertyFormatter("enabled"), - new fjs.PropertyFormatter("title"), - new fjs.PropertyFormatter("description"), + new fjs.PropertyFormatter("title",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.PropertyFormatter("description",new fjs.SingleCommentFormatter("Leave empty to disable")), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("customColor"), - new fjs.PropertyFormatter("url"), + new fjs.PropertyFormatter("customColor",new fjs.SingleCommentFormatter("Leave empty to use default color")), + new fjs.PropertyFormatter("url",new fjs.SingleCommentFormatter("URL. Leave empty to disable")), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("image"), - new fjs.PropertyFormatter("thumbnail"), + new fjs.PropertyFormatter("image",new fjs.SingleCommentFormatter("Image URL. Leave empty to disable")), + new fjs.PropertyFormatter("thumbnail",new fjs.SingleCommentFormatter("Image URL. Leave empty to disable")), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("footer"), + new fjs.PropertyFormatter("footer",new fjs.SingleCommentFormatter("Leave empty to disable")), + new fjs.MultiCommentFormatter("Embed fields. Set to empty list [] to disable."), new fjs.ArrayFormatter("fields",true,new fjs.ObjectFormatter(null,false,[ new fjs.PropertyFormatter("name"), new fjs.PropertyFormatter("value"), @@ -328,53 +499,70 @@ export const defaultPanelsFormatter = new fjs.ArrayFormatter(null,true,new fjs.O new fjs.PropertyFormatter("timestamp"), ]), new fjs.ObjectFormatter("settings",true,[ - new fjs.PropertyFormatter("dropdownPlaceholder"), + new fjs.PropertyFormatter("dropdownPlaceholder",new fjs.SingleCommentFormatter("Leave empty to use default.")), + new fjs.PropertyFormatter("maximumButtonsPerRow"), new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Display the maximum amount of tickets per user."), new fjs.PropertyFormatter("enableMaxTicketsWarningInText"), new fjs.PropertyFormatter("enableMaxTicketsWarningInEmbed"), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("describeOptionsLayout"), + new fjs.MultiCommentFormatter("Automatically generate option descriptions from (config/options.jsonc)."), + new fjs.PropertyFormatter("describeOptionsLayout",new fjs.SingleCommentFormatter("Choices: simple, normal, detailed")), new fjs.PropertyFormatter("describeOptionsCustomTitle"), new fjs.PropertyFormatter("describeOptionsInText"), new fjs.PropertyFormatter("describeOptionsInEmbedFields"), new fjs.PropertyFormatter("describeOptionsInEmbedDescription"), ]), -])) +]))) -export const defaultTranscriptsFormatter = new fjs.ObjectFormatter(null,true,[ +export const defaultTranscriptsFormatter = new fjs.TopLevelCommentFormatter(new fjs.MultiCommentFormatter([ + "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.", + ].join("\n")),new fjs.ObjectFormatter(null,true,[ new fjs.ObjectFormatter("general",true,[ new fjs.PropertyFormatter("enabled"), new fjs.TextFormatter(""), + new fjs.MultiCommentFormatter("Choose which users and channel get the generated transcript."), new fjs.PropertyFormatter("enableChannel"), new fjs.PropertyFormatter("enableCreatorDM"), new fjs.PropertyFormatter("enableParticipantDM"), new fjs.PropertyFormatter("enableActiveAdminDM"), new fjs.PropertyFormatter("enableEveryAdminDM"), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("channel"), - new fjs.PropertyFormatter("mode"), + new fjs.PropertyFormatter("channel",new fjs.SingleCommentFormatter("Where to send transcripts. Leave empty when disabled.")), + new fjs.PropertyFormatter("mode",new fjs.SingleCommentFormatter("The type of transcript to use. Choices: html, text")), ]), new fjs.ObjectFormatter("embedSettings",true,[ - new fjs.PropertyFormatter("customColor"), + new fjs.MultiCommentFormatter("Customise the embed which contains the generated transcript file or URL."), + new fjs.PropertyFormatter("customColor",new fjs.SingleCommentFormatter("Leave empty to use default color")), new fjs.PropertyFormatter("listAllParticipants"), new fjs.PropertyFormatter("includeTicketStats"), ]), new fjs.ObjectFormatter("textTranscriptStyle",true,[ - new fjs.PropertyFormatter("layout"), + new fjs.MultiCommentFormatter("Customise layout of the text transcripts."), + new fjs.PropertyFormatter("layout",new fjs.SingleCommentFormatter("Choices: simple, normal, detailed")), new fjs.PropertyFormatter("includeStats"), new fjs.PropertyFormatter("includeIds"), new fjs.PropertyFormatter("includeEmbeds"), new fjs.PropertyFormatter("includeFiles"), new fjs.PropertyFormatter("includeBotMessages"), new fjs.TextFormatter(""), - new fjs.PropertyFormatter("fileMode"), - new fjs.PropertyFormatter("customFileName"), + new fjs.PropertyFormatter("fileMode",new fjs.SingleCommentFormatter("How to name the transcript file? Choices: custom, channel-name, channel-id, user-name, user-id")), + new fjs.PropertyFormatter("customFileName",new fjs.SingleCommentFormatter("Custom filename without extension")), ]), new fjs.ObjectFormatter("htmlTranscriptStyle",true,[ + new fjs.MultiCommentFormatter("Customise layout of the HTML transcripts."), new fjs.ObjectFormatter("background",true,[ new fjs.PropertyFormatter("enableCustomBackground"), - new fjs.PropertyFormatter("backgroundColor"), - new fjs.PropertyFormatter("backgroundImage"), + new fjs.PropertyFormatter("backgroundColor",new fjs.SingleCommentFormatter("Leave empty to use Open Ticket color (#f8ba00)")), + new fjs.PropertyFormatter("backgroundImage",new fjs.SingleCommentFormatter("Image URL to fill entire background. Leave empty to disable")), ]), new fjs.ObjectFormatter("header",true,[ new fjs.PropertyFormatter("enableCustomHeader"), @@ -395,4 +583,4 @@ export const defaultTranscriptsFormatter = new fjs.ObjectFormatter(null,true,[ new fjs.PropertyFormatter("imageUrl"), ]), ]), -]) \ No newline at end of file +])) \ No newline at end of file diff --git a/src/data/framework/helpMenuLoader.ts b/src/data/framework/helpMenuLoader.ts index 27dbf4e..ab29a72 100644 --- a/src/data/framework/helpMenuLoader.ts +++ b/src/data/framework/helpMenuLoader.ts @@ -20,11 +20,11 @@ export async function loadAllHelpMenuComponents(){ if (!generalConfig) return const prefix = generalConfig.data.prefix - const enableDeleteWithoutTranscript = generalConfig.data.system.enableDeleteWithoutTranscript + const enableDeleteWithoutTranscript = generalConfig.data.ticketSystem.enableDeleteWithoutTranscript const allowedCommands: string[] = [] - for (const key in generalConfig.data.system.permissions){ - if (generalConfig.data.system.permissions[key] != "none") allowedCommands.push(key) + for (const key in generalConfig.data.permissions){ + if (generalConfig.data.permissions[key] != "none") allowedCommands.push(key) } const general = helpmenu.get("opendiscord:general") diff --git a/src/data/framework/postLoader.ts b/src/data/framework/postLoader.ts index c23b881..06cfce4 100644 --- a/src/data/framework/postLoader.ts +++ b/src/data/framework/postLoader.ts @@ -7,7 +7,7 @@ export async function loadAllPosts(){ if (!transcriptConfig) return //LOGS CHANNEL - if (generalConfig.data.system.logs.enabled) opendiscord.posts.add(new api.ODPost("opendiscord:logs",generalConfig.data.system.logs.channel)) + if (generalConfig.data.logs.enabled) opendiscord.posts.add(new api.ODPost("opendiscord:logs",generalConfig.data.logs.channel)) //TRANSCRIPTS CHANNEL if (transcriptConfig.data.general.enabled && transcriptConfig.data.general.enableChannel) opendiscord.posts.add(new api.ODPost("opendiscord:transcripts",transcriptConfig.data.general.channel)) diff --git a/src/data/openticket/optionLoader.ts b/src/data/openticket/optionLoader.ts index a9277c0..de8639d 100644 --- a/src/data/openticket/optionLoader.ts +++ b/src/data/openticket/optionLoader.ts @@ -71,9 +71,6 @@ export const loadTicketOption = (option:api.ODOptionsJsonConfig_TicketOption): a new api.ODOptionData("opendiscord:channel-prefix",option.channel.prefix), new api.ODOptionData("opendiscord:channel-suffix",option.channel.suffix), new api.ODOptionData("opendiscord:channel-category",option.channel.category), - new api.ODOptionData("opendiscord:channel-category-closed",option.channel.closedCategory), - new api.ODOptionData("opendiscord:channel-category-backup",option.channel.backupCategory), - new api.ODOptionData("opendiscord:channel-categories-claimed",option.channel.claimedCategory), new api.ODOptionData("opendiscord:channel-topic",option.channel.topic), new api.ODOptionData("opendiscord:dm-message-enabled",option.dmMessage.enabled), diff --git a/src/data/openticket/panelLoader.ts b/src/data/openticket/panelLoader.ts index d2abbb2..df9b150 100644 --- a/src/data/openticket/panelLoader.ts +++ b/src/data/openticket/panelLoader.ts @@ -93,7 +93,7 @@ export function describePanelOptions(mode:"fields"|"text", panel:api.ODPanel): { } if (layout == "detailed"){ const optionAdmins = [...opt.get("opendiscord:admins").value] - if (generalConfig.data.system.showGlobalAdminsInPanelRoles){ + if (generalConfig.data.ticketSystem.showGlobalAdminsInPanelRoles){ for (const admin of generalConfig.data.globalAdmins){ if (!optionAdmins.includes(admin)) optionAdmins.push(admin) } @@ -147,7 +147,7 @@ export function describePanelOptions(mode:"fields"|"text", panel:api.ODPanel): { } if (layout == "detailed"){ const optionAdmins = [...opt.get("opendiscord:admins").value] - if (generalConfig.data.system.showGlobalAdminsInPanelRoles){ + if (generalConfig.data.ticketSystem.showGlobalAdminsInPanelRoles){ for (const admin of generalConfig.data.globalAdmins){ if (!optionAdmins.includes(admin)) optionAdmins.push(admin) } diff --git a/src/index.ts b/src/index.ts index 0f8f957..2c61a46 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,7 @@ INFORMATION: ============ - Open Ticket v4.1.3 - ยฉ DJdj Development + Open Ticket v4.2.0 - ยฉ DJdj Development support us: https://github.com/sponsors/DJj123dj discord: https://discord.dj-dj.be @@ -151,7 +151,8 @@ const main = async () => { if (opendiscord.sharedFuses.getFuse("emojiTitleStyleLoading")){ //set emoji style based on config - opendiscord.sharedFuses.setFuse("emojiTitleStyle",generalConfig.data.system.emojiStyle) + const emojiStyle = (generalConfig.data && generalConfig.data.ticketSystem && generalConfig.data.ticketSystem.emojiStyle) ? generalConfig.data.ticketSystem.emojiStyle : "before" + opendiscord.sharedFuses.setFuse("emojiTitleStyle",emojiStyle) } //load database @@ -225,7 +226,7 @@ const main = async () => { } //handle data migration (PART 2) - if (lastVersion) await (await import("./core/startup/manageMigration.js")).loadAllAfterInitVersionMigrations(lastVersion) + if (lastVersion) await (await import("./core/startup/manageMigration.js")).loadAfterStartupMigrations(lastVersion) //load config checker opendiscord.log("Loading config checker...","system") @@ -253,7 +254,7 @@ const main = async () => { if (opendiscord.sharedFuses.getFuse("checkerTranslationLoading")){ await (await import("./data/framework/checkerLoader.js")).loadAllConfigCheckerTranslations() } - await opendiscord.events.get("onCheckerTranslationLoad").emit([opendiscord.checkers.translation,((generalConfig && generalConfig.data.system && generalConfig.data.system.useTranslatedConfigChecker) ? generalConfig.data.system.useTranslatedConfigChecker : false),opendiscord.checkers]) + await opendiscord.events.get("onCheckerTranslationLoad").emit([opendiscord.checkers.translation,((generalConfig && generalConfig.data.ticketSystem && generalConfig.data.ticketSystem.useTranslatedConfigChecker) ? generalConfig.data.ticketSystem.useTranslatedConfigChecker : false),opendiscord.checkers]) await opendiscord.events.get("afterCheckerTranslationsLoaded").emit([opendiscord.checkers.translation,opendiscord.checkers]) //render config checker