From 86a5a1a2ca0d171cd2e96e1f29ed55d836a2d93c Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Tue, 27 Dec 2022 11:38:32 +0100 Subject: [PATCH 1/6] v3.1.0 push 1 --- README.md | 4 +- config.json | 21 +++++++-- core/checker.js | 4 +- core/reactionRoles.js | 93 +++++++++++++++++++------------------- core/utils/configParser.js | 2 +- core/utils/getDropdown.js | 23 ++++++++-- core/utils/getEmbed.js | 12 +++-- package.json | 2 +- 8 files changed, 99 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 01c1a56..a1a838b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Open Ticket -[![discord](https://img.shields.io/badge/discord-join%20our%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) [![version](https://img.shields.io/badge/version-3.0.1-brightgreen.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/releases/tag/v3.0.1) [![discord.js](https://img.shields.io/badge/discord.js-v14-CB3837.svg?style=flat-square&logo=npm)]() [![license](https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/blob/main/LICENSE) [![documentation](https://img.shields.io/badge/documentation-Click%20Here-yellow.svg?style=flat-square)](https://docs.openticket.dj-dj.be) +[![discord](https://img.shields.io/badge/discord-join%20our%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) [![version](https://img.shields.io/badge/version-3.1.0-brightgreen.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/releases/tag/v3.1.0) [![discord.js](https://img.shields.io/badge/discord.js-v14-CB3837.svg?style=flat-square&logo=npm)]() [![license](https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/blob/main/LICENSE) [![documentation](https://img.shields.io/badge/documentation-Click%20Here-yellow.svg?style=flat-square)](https://docs.openticket.dj-dj.be) Open ticket is the most configurable open-source ticket bot for discord! Made with the newest technologies. Like: Slash commands, transcripts, multiple ticket types, buttons & dropdowns! Start using it now, you can do anything! @@ -52,7 +52,7 @@ Start using it now, you can do anything! ## information -_v3.0.1_ +_v3.1.0_ changelog: [click here](https://docs.openticket.dj-dj.be/other/changelog) diff --git a/config.json b/config.json index e449367..c9e1e82 100644 --- a/config.json +++ b/config.json @@ -92,7 +92,7 @@ "dropdown":false, "enableFooter":false, - "footer":"Open Ticket v3.0.1 - I'm a footer!", + "footer":"Open Ticket v3.1.0 - I'm a footer!", "enableThumbnail":false, "thumbnail":"https://www.example.com/catmemes/cat.png", @@ -101,8 +101,23 @@ "color":"#ffffff", "options":["general","apply"], - "enableTicketExplaination":true, - "enableMaxTicketsWarning":true + + "other":{ + "enableTicketExplaination":true, + "enableMaxTicketsWarning":true, + "customDropdownPlaceholder":{ + "enable":false, + "text":"Choose a ticket" + }, + "customCategoryText":{ + "enable":false, + "text":"choose a category:" + }, + "embedTitleURL":{ + "enable":false, + "url":"https://www.dj-dj.be/projects/open-ticket" + } + } } ] } \ No newline at end of file diff --git a/core/checker.js b/core/checker.js index 6269018..9da940e 100644 --- a/core/checker.js +++ b/core/checker.js @@ -312,8 +312,8 @@ exports.checker = async () => { } //ticket explaination & max tickets warning - checkType(input.enableTicketExplaination,"boolean",path+"/enableTicketExplaination") - checkType(input.enableMaxTicketsWarning,"boolean",path+"/enableMaxTicketsWarning") + checkType(input.other.enableTicketExplaination,"boolean",path+"/other/enableTicketExplaination") + checkType(input.other.enableMaxTicketsWarning,"boolean",path+"/other/enableMaxTicketsWarning") //OPTIONS!!! var counter = 0 diff --git a/core/reactionRoles.js b/core/reactionRoles.js index 31b619e..de34b8f 100644 --- a/core/reactionRoles.js +++ b/core/reactionRoles.js @@ -12,64 +12,65 @@ module.exports = async () => { const chalk = await (await import("chalk")).default client.on("interactionCreate",(interaction) => { - if (!interaction.isButton()) return - if (!interaction.customId.startsWith("newR")) return + if (!interaction.isButton() && !interaction.isStringSelectMenu()) return + if (interaction.isButton() && !interaction.customId.startsWith("newR")) return + if (interaction.isStringSelectMenu() && !(interaction.customId == "OTdropdownMenu")) return interaction.deferUpdate() - if (interaction.customId.startsWith("newR")){ - const optionid = interaction.customId.split("newR")[1] - if (!optionid){ - interaction.reply({embeds:[bot.errorLog.serverError(l.errors.roleDoesntExist)]}) - return - } - try { + const optionidRaw = interaction.isStringSelectMenu() ? interaction.values[0] : interaction.customId + const optionid = optionidRaw.split("newR")[1] + if (!optionid){ + interaction.reply({embeds:[bot.errorLog.serverError(l.errors.roleDoesntExist)]}) + return + } - const option = require("./utils/getButton").getOption(optionid) - /**@type {"add"|"remove"|"add&remove"} */ - const mode = option.mode - const user = interaction.member + try { + + const option = require("./utils/getButton").getOption(optionid) + /**@type {"add"|"remove"|"add&remove"} */ + const mode = option.mode + const user = interaction.member + + if (mode == "add"){ + option.roles.forEach((role) => { + interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role) + + log("system","added role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) + const apirole = interaction.guild.roles.cache.find(r => r.id == role) + APIEvents.onReactionRole("add","add",apirole,interaction.user,interaction.channel,interaction.guild,new Date()) + }) + + }else if (mode == "remove"){ + option.roles.forEach((role) => { + interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role) + + log("system","removed role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) + const apirole = interaction.guild.roles.cache.find(r => r.id == role) + APIEvents.onReactionRole("remove","remove",apirole,interaction.user,interaction.channel,interaction.guild,new Date()) + }) - if (mode == "add"){ - option.roles.forEach((role) => { - interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role) - + }else if (mode == "add&remove"){ + option.roles.forEach((role) => { + if (interaction.guild.members.cache.find(u => u.id == user.id).roles.cache.has(role)){ + interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role) + log("system","added role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) const apirole = interaction.guild.roles.cache.find(r => r.id == role) - APIEvents.onReactionRole("add","add",apirole,interaction.user,interaction.channel,interaction.guild,new Date()) - }) - - }else if (mode == "remove"){ - option.roles.forEach((role) => { - interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role) + APIEvents.onReactionRole("add","add&remove",apirole,interaction.user,interaction.channel,interaction.guild,new Date()) + }else { + interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role) log("system","removed role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) const apirole = interaction.guild.roles.cache.find(r => r.id == role) - APIEvents.onReactionRole("remove","remove",apirole,interaction.user,interaction.channel,interaction.guild,new Date()) - }) - - }else if (mode == "add&remove"){ - option.roles.forEach((role) => { - if (interaction.guild.members.cache.find(u => u.id == user.id).roles.cache.has(role)){ - interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role) - - log("system","added role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) - const apirole = interaction.guild.roles.cache.find(r => r.id == role) - APIEvents.onReactionRole("add","add&remove",apirole,interaction.user,interaction.channel,interaction.guild,new Date()) - }else { - interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role) - - log("system","removed role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) - const apirole = interaction.guild.roles.cache.find(r => r.id == role) - APIEvents.onReactionRole("remove","add&remove",apirole,interaction.user,interaction.channel,interaction.guild,new Date()) - } - }) - } - - }catch{ - interaction.channel.send({embeds:[bot.errorLog.serverError(l.errors.somethingWentWrong)]}) + APIEvents.onReactionRole("remove","add&remove",apirole,interaction.user,interaction.channel,interaction.guild,new Date()) + } + }) } + + }catch{ + interaction.channel.send({embeds:[bot.errorLog.serverError(l.errors.somethingWentWrong)]}) } }) } \ No newline at end of file diff --git a/core/utils/configParser.js b/core/utils/configParser.js index 20797cd..e5c82d1 100644 --- a/core/utils/configParser.js +++ b/core/utils/configParser.js @@ -16,7 +16,7 @@ const l = bot.language //OTConfigMessage -/**@typedef {{id: string, name: string, description: string, dropdown: boolean, enableFooter: boolean, footer: string, enableThumbnail: boolean, thumbnail: string, enableCustomColor: boolean, color: string, options: string[], enableTicketExplaination: boolean, enableMaxTicketsWarning: boolean}} OTConfigMessage*/ +/**@typedef {{id: string, name: string, description: string, dropdown: boolean, enableFooter: boolean, footer: string, enableThumbnail: boolean, thumbnail: string, enableCustomColor: boolean, color: string, options: string[], other:{enableTicketExplaination: boolean, enableMaxTicketsWarning: boolean, customDropdownPlaceholder:{enable:Boolean,text:String}, customCategoryText:{enable:Boolean,text:String}, embedTitleURL:{enable:Boolean,url:String} } }} OTConfigMessage*/ //StringOptions /**@typedef {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"adminroles"|"channelprefix"|"category"|"message"|"enableDmOnOpen"|"ticketmessage"|"thumbnail"|"closedCategory"} OTTicketStringOptions */ diff --git a/core/utils/getDropdown.js b/core/utils/getDropdown.js index 2801c68..5b21d00 100644 --- a/core/utils/getDropdown.js +++ b/core/utils/getDropdown.js @@ -7,24 +7,26 @@ const configParser = require("./configParser") /** * * @param {String[]} ids + * @param {String|undefined|false} placeholder * @returns {discord.StringSelectMenuBuilder|false} */ -exports.getDropdown = (ids) => { +exports.getDropdown = (ids,placeholder) => { const dropdown = new discord.StringSelectMenuBuilder() .setCustomId("OTdropdownMenu") .setDisabled(false) .setMaxValues(1) .setMinValues(1) - .setPlaceholder(l.messages.chooseATicket) + .setPlaceholder(placeholder || l.messages.chooseATicket) .addOptions( new discord.SelectMenuOptionBuilder() .setDefault(true) - .setLabel(l.messages.chooseATicket) + .setLabel(placeholder || l.messages.chooseATicket) .setValue("OTChooseTicket") ) ids.forEach((id) => { const option = configParser.getTicketById(id,true) + const roleoption = configParser.getRoleById(id,true) if (option){ const selectComponent = new discord.SelectMenuOptionBuilder() .setDefault(false) @@ -37,8 +39,23 @@ exports.getDropdown = (ids) => { if (option.icon) selectComponent.setEmoji(option.icon) } + dropdown.addOptions(selectComponent) + + }else if (roleoption){ + const selectComponent = new discord.SelectMenuOptionBuilder() + .setDefault(false) + .setValue("OTnewR"+roleoption.id) + + if (!roleoption.label && !roleoption.icon){ + selectComponent.setLabel("OT ERROR: no description/emoji") + }else{ + if (roleoption.label) selectComponent.setLabel(roleoption.label) + if (roleoption.icon) selectComponent.setEmoji(roleoption.icon) + } + dropdown.addOptions(selectComponent) } + }) diff --git a/core/utils/getEmbed.js b/core/utils/getEmbed.js index aa44034..1abb837 100644 --- a/core/utils/getEmbed.js +++ b/core/utils/getEmbed.js @@ -43,9 +43,12 @@ exports.createEmbed = (id) => { embed.setColor(config.main_color) } + if (data.other.embedTitleURL.enable) embed.setURL(data.other.embedTitleURL) + var description = data.description - if (data.enableTicketExplaination){ - description = description+"\n\n__"+l.messages.chooseCategory+"__\n" + if (data.other.enableTicketExplaination){ + const chooseCategoryMSG = data.other.customCategoryText.enable ? data.other.customCategoryText.text : l.messages.chooseCategory + description = description+"\n\n__"+chooseCategoryMSG+"__\n" var ticketExplainations = [] buttonData.forEach((button) => { @@ -56,7 +59,7 @@ exports.createEmbed = (id) => { description = description+ticketExplainations.join("\n\n") } - if (data.enableMaxTicketsWarning){ + if (data.other.enableMaxTicketsWarning){ description = description+"\n\n"+l.commands.maxTicketWarning.replace("{0}",config.system.max_allowed_tickets) } @@ -92,7 +95,8 @@ exports.createEmbed = (id) => { //create the component IF DROPDOWN is true }else{ const ids = data.options - const dropdown = require("./getDropdown").getDropdown(ids) + const customPlaceholder = data.other.customDropdownPlaceholder.enable ? data.other.customDropdownPlaceholder.text : false + const dropdown = require("./getDropdown").getDropdown(ids,customPlaceholder) var componentRows = [ new discord.ActionRowBuilder() .setComponents(dropdown) diff --git a/package.json b/package.json index fd25aa9..9a74f35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-ticket", - "version": "3.0.1", + "version": "3.1.0", "description": "This is an open-source discord ticket bot, you can configure it and it comes with cool features like a transcript.", "main": "index.js", "scripts": { From ae002e168b6046c05d20b0c82850f2b69769d274 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Tue, 27 Dec 2022 17:35:01 +0100 Subject: [PATCH 2/6] v3.1.0 push 2 --- .gitignore | 1 + core/dynamicdatabase/dynamicfiles/database.js | 66 ++++++++++++++ core/dynamicdatabase/dynamicfiles/local.js | 6 +- core/dynamicdatabase/storage.js | 10 +-- .../handlers/accepted/closing.js | 4 +- .../handlers/sendTranscript.js | 4 +- .../handlers/verifyBars.js | 24 +++-- core/reactionRoles.js | 14 ++- core/slashSystem/autoSlashUpdate.js | 88 +++++++++++++++++++ core/slashSystem/slashEnable.js | 2 + core/ticketActions/ticketOpener.js | 12 ++- index.js | 17 +++- language/german.json | 3 + storage/database.json | 12 +++ 14 files changed, 239 insertions(+), 24 deletions(-) create mode 100644 core/dynamicdatabase/dynamicfiles/database.js create mode 100644 core/slashSystem/autoSlashUpdate.js create mode 100644 storage/database.json diff --git a/.gitignore b/.gitignore index a45912f..b57bba5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ devConfig5.json openticketdebug.txt developerChangelog.md storage/dynamicDB/ +storage/slashcmdEnabled.txt storage/.DS_Store .vscode/ livestatus.json diff --git a/core/dynamicdatabase/dynamicfiles/database.js b/core/dynamicdatabase/dynamicfiles/database.js new file mode 100644 index 0000000..f89955e --- /dev/null +++ b/core/dynamicdatabase/dynamicfiles/database.js @@ -0,0 +1,66 @@ +const fs = require("fs") +const location = "./storage/database.json" + + +/**@returns {[{category:String, key:String, value:String}]}*/ +function getData(){ + return JSON.parse(fs.readFileSync(location).toString()) +} +/**@param {[{category:String, key:String, value:String}]} data*/ +function setData(data){ + fs.writeFileSync(location,JSON.stringify(data,null,"\t")) +} + +exports.set = (category,key,value) => { + const currentData = getData() + const exists = currentData.find((d) => (d.category == category) && (d.key == key)) ? true : false + var newData = [] + if (exists){ + currentData.forEach((d,i) => { + if (d.category == category && d.key == key){ + newData.push({category,key,value}) + }else{ + newData.push(d) + } + }) + }else{ + currentData.push({category,key,value}) + newData = currentData + } + + setData(newData) + return exists +} +/** + * @param {String} category + * @param {String} key + * @returns {String|false} + */ +exports.get = (category,key) => { + const currentData = getData() + const tempresult = currentData.find((d) => (d.category == category) && (d.key == key)) + const result = tempresult ? tempresult.value : false + return result +} +/** + * @param {String} category + * @param {String} key + * @param {String} value + */ +exports.delete = (category,key) => { + const currentData = getData() + const exists = currentData.find((d) => (d.category == category) && (d.key == key)) ? true : false + var newData = [] + if (exists){ + currentData.forEach((d,i) => { + if (!(d.category == category && d.key == key)){ + newData.push(d) + } + }) + }else{ + newData = currentData + } + + setData(newData) + return exists +} \ No newline at end of file diff --git a/core/dynamicdatabase/dynamicfiles/local.js b/core/dynamicdatabase/dynamicfiles/local.js index fec0b6c..4ee9d79 100644 --- a/core/dynamicdatabase/dynamicfiles/local.js +++ b/core/dynamicdatabase/dynamicfiles/local.js @@ -36,4 +36,8 @@ exports.get = (category,id) => { exports.delete = (category,id) => { ls.removeItem(category+"--"+id) return true -} \ No newline at end of file +} + +this.set("category","key","value") +this.get("category","key",) +this.delete("category","key") \ No newline at end of file diff --git a/core/dynamicdatabase/storage.js b/core/dynamicdatabase/storage.js index 80ad75d..dcc4060 100644 --- a/core/dynamicdatabase/storage.js +++ b/core/dynamicdatabase/storage.js @@ -1,11 +1,7 @@ -//Do not change this without knowing what you are doing!! -const databaseFile = "local" -//Do not change this without knowing what you are doing!! - - try { - var db = require("./dynamicfiles/local") -}catch{ + var db = require("./dynamicfiles/database") +}catch(err){ + console.log(err) console.log("I couldn't find the database file! (location: ./core/dynamicdatabase/storage.js:2)") process.exit(1) } diff --git a/core/interactionHandlers/handlers/accepted/closing.js b/core/interactionHandlers/handlers/accepted/closing.js index 27dc578..17776aa 100644 --- a/core/interactionHandlers/handlers/accepted/closing.js +++ b/core/interactionHandlers/handlers/accepted/closing.js @@ -22,7 +22,9 @@ module.exports = () => { if (!interaction.isButton()) return if (interaction.customId != "OTcloseTicketTrue") return - interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} if (closeTicketButtonChecker == true) return closeTicketButtonChecker = true diff --git a/core/interactionHandlers/handlers/sendTranscript.js b/core/interactionHandlers/handlers/sendTranscript.js index c1f1c65..6ac442c 100644 --- a/core/interactionHandlers/handlers/sendTranscript.js +++ b/core/interactionHandlers/handlers/sendTranscript.js @@ -20,7 +20,9 @@ module.exports = () => { if (!interaction.isButton()) return if (interaction.customId != "OTsendTranscript") return - interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} const tsmsg = await interaction.channel.send({embeds:[bot.embeds.commands.sendTranscriptEmbed(false,interaction.channel,interaction.user)]}) const channelmessages = await interaction.channel.messages.fetch() diff --git a/core/interactionHandlers/handlers/verifyBars.js b/core/interactionHandlers/handlers/verifyBars.js index a365bcd..bb2ae74 100644 --- a/core/interactionHandlers/handlers/verifyBars.js +++ b/core/interactionHandlers/handlers/verifyBars.js @@ -20,7 +20,9 @@ module.exports = () => { if (!interaction.isButton()) return if (interaction.customId != "OTcloseTicket") return - interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} interaction.message.edit({components:[bot.buttons.verifybars.closeVerifyBar]}) }) @@ -28,7 +30,9 @@ module.exports = () => { if (!interaction.isButton()) return if (interaction.customId != "OTcloseTicketFalse") return - interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} interaction.message.edit({components:[bot.buttons.close.openRowNormal]}) }) @@ -37,7 +41,9 @@ module.exports = () => { if (!interaction.isButton()) return if (interaction.customId != "OTdeleteTicket") return - interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} interaction.message.edit({components:[bot.buttons.verifybars.deleteVerifyBar]}) }) @@ -45,7 +51,9 @@ module.exports = () => { if (!interaction.isButton()) return if (interaction.customId != "OTdeleteTicketFalse") return - interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} interaction.message.edit({components:[bot.buttons.close.openRowNormal]}) }) @@ -54,7 +62,9 @@ module.exports = () => { if (!interaction.isButton()) return if (interaction.customId != "OTdeleteTicket1") return - interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} interaction.message.edit({components:[bot.buttons.verifybars.delete1VerifyBar]}) }) @@ -62,7 +72,9 @@ module.exports = () => { if (!interaction.isButton()) return if (interaction.customId != "OTdeleteTicketFalse1") return - interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} interaction.message.edit({components:[bot.buttons.close.closeCommandRow]}) }) } \ No newline at end of file diff --git a/core/reactionRoles.js b/core/reactionRoles.js index de34b8f..fc8317a 100644 --- a/core/reactionRoles.js +++ b/core/reactionRoles.js @@ -16,14 +16,20 @@ module.exports = async () => { if (interaction.isButton() && !interaction.customId.startsWith("newR")) return if (interaction.isStringSelectMenu() && !(interaction.customId == "OTdropdownMenu")) return - interaction.deferUpdate() + + const optionidRaw = interaction.isStringSelectMenu() ? interaction.values[0] : interaction.customId + if (!optionidRaw.includes("newR")) return const optionid = optionidRaw.split("newR")[1] if (!optionid){ interaction.reply({embeds:[bot.errorLog.serverError(l.errors.roleDoesntExist)]}) return + }else{ + try { + interaction.deferUpdate() + } catch{} } try { @@ -53,14 +59,14 @@ module.exports = async () => { }else if (mode == "add&remove"){ option.roles.forEach((role) => { - if (interaction.guild.members.cache.find(u => u.id == user.id).roles.cache.has(role)){ - interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role) + if (!interaction.guild.members.cache.find(u => u.id == user.id).roles.cache.has(role)){ + interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role) log("system","added role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) const apirole = interaction.guild.roles.cache.find(r => r.id == role) APIEvents.onReactionRole("add","add&remove",apirole,interaction.user,interaction.channel,interaction.guild,new Date()) }else { - interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role) + interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role) log("system","removed role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) const apirole = interaction.guild.roles.cache.find(r => r.id == role) diff --git a/core/slashSystem/autoSlashUpdate.js b/core/slashSystem/autoSlashUpdate.js new file mode 100644 index 0000000..3ef73c6 --- /dev/null +++ b/core/slashSystem/autoSlashUpdate.js @@ -0,0 +1,88 @@ +const discord = require("discord.js") +const bot = require("../../index") +const client = require("../../index").client +const config = bot.config +const configParser = require("../utils/configParser") + +const act = discord.ApplicationCommandType +const acot = discord.ApplicationCommandOptionType + +module.exports = async () => { + bot.errorLog.log("info","auto-updating slash commands...") + const sid = config.server_id + + const ids = configParser.getTicketValuesArray("id") + /**@type {[{name:String,value:String}]} */ + var choices = [] + ids.forEach((id) => { + const option = configParser.getTicketById(id) + if (option){ + choices.push({name:option.name,value:option.id}) + } + }) + + /**@type {[{name:String,value:String}]} */ + var msgchoices = [] + config.messages.forEach((msg) => { + msgchoices.push({name:msg.id,value:msg.id}) + }) + + //slashtranslation + const ST = require("../../language/slashcmds/slash.json").data + + //create a ticket (/new or /ticket) + client.application.commands.create({ + name:"ticket", + description:"Create a ticket!", + descriptionLocalizations:ST.newticket, + defaultPermission:true, + type:act.ChatInput, + options:[ + { + type:acot.String, + name:"type", + description:"The type of ticket.", + required:true, + choices:choices + } + ] + },sid) + + client.application.commands.create({ + name:"new", + description:"Create a ticket!", + defaultPermission:true, + type:act.ChatInput, + descriptionLocalizations:ST.newticket, + options:[ + { + type:acot.String, + name:"type", + description:"The type of ticket.", + required:true, + choices:choices + + } + ] + },sid) + + //msg + client.application.commands.create({ + name:"message", + description:"Create a ticket message.", + defaultPermission:true, + descriptionLocalizations:ST.message, + type:act.ChatInput, + options:[ + { + type:acot.String, + name:"id", + description:"The message id.", + required:true, + choices:msgchoices, + max_length:30 + + } + ] + },sid) +} \ No newline at end of file diff --git a/core/slashSystem/slashEnable.js b/core/slashSystem/slashEnable.js index cc39c23..299b5e7 100644 --- a/core/slashSystem/slashEnable.js +++ b/core/slashSystem/slashEnable.js @@ -34,6 +34,8 @@ module.exports = async () => { process.stdout.cursorTo(0) process.stdout.write("[status] there are "+chalk.blue(readystats+" out of 12")+" commands ready! (this can take up to 40 seconds)") if (readystats >= 12){ + const fs = require("fs") + fs.writeFileSync("./storage/slashcmdEnabled.txt","true") console.log(chalk.green("\nready!")) console.log(chalk.blue("you can now start the bot with "+chalk.bgBlue("'npm start'")+"!")) process.exit(1) diff --git a/core/ticketActions/ticketOpener.js b/core/ticketActions/ticketOpener.js index 1221ad2..3ff877b 100755 --- a/core/ticketActions/ticketOpener.js +++ b/core/ticketActions/ticketOpener.js @@ -13,7 +13,9 @@ module.exports = () => { client.on("interactionCreate",(interaction) => { if (!interaction.isStringSelectMenu()) return if (interaction.customId != "OTdropdownMenu") return - if (interaction.values.includes("OTChooseTicket")) interaction.deferUpdate() + if (interaction.values.includes("OTChooseTicket")){ + interaction.deferUpdate() + } }) @@ -50,11 +52,15 @@ module.exports = () => { if (currentTicketOptions == false) return interaction.reply({embeds:[bot.errorLog.serverError(l.errors.anotherOption)]}) if (interaction.isButton()){ - interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} }else if (interaction.isChatInputCommand()){ interaction.reply({embeds:[bot.errorLog.success(l.messages.createdTitle,l.messages.createdDescription)]}) }else if (interaction.isStringSelectMenu()){ - await interaction.deferUpdate() + try { + interaction.deferUpdate() + } catch{} } if (storage.get("ticketStorage",interaction.member.id) == null || storage.get("ticketStorage",interaction.member.id) == "false"|| Number(storage.get("ticketStorage",interaction.member.id)) < config.system.max_allowed_tickets){ diff --git a/index.js b/index.js index e529ec6..94ce9d2 100644 --- a/index.js +++ b/index.js @@ -124,6 +124,12 @@ client.on('ready',async () => { setStatus(config.status.type,config.status.text) } + if (fs.existsSync("./storage/slashcmdEnabled.txt")){ + /**@type {"true"|"false"} */ + const data = fs.readFileSync("./storage/slashcmdEnabled.txt").toString() + if (data === "true"){require("./core/slashSystem/autoSlashUpdate")()} + }else{fs.writeFileSync("./storage/slashcmdEnabled.txt","false")} + log("system","bot logged in!") try { @@ -150,10 +156,19 @@ client.on('ready',async () => { if (config.status.enabled){ setStatus(config.status.type,config.status.text) } + if (fs.existsSync("./storage/slashcmdEnabled.txt")){ + /**@type {"true"|"false"} */ + const data = fs.readFileSync("./storage/slashcmdEnabled.txt").toString() + if (data === "true"){require("./core/slashSystem/autoSlashUpdate")()} + }else{fs.writeFileSync("./storage/slashcmdEnabled.txt","false")} log("system","bot logged in!") - await client.guilds.cache.find((g) => g.id == config.server_id).members.fetch() + try { + await client.guilds.cache.find((g) => g.id == config.server_id).members.fetch() + }catch{ + this.errorLog.log("info","tried to cache user information, failed!") + } }else{ console.log(chalk.red("STARTING IN ")+chalk.blue("SLASH MODE")+chalk.red("...")) this.errorLog.log("debug","slashmode activated") diff --git a/language/german.json b/language/german.json index 3a31cda..a555b6c 100644 --- a/language/german.json +++ b/language/german.json @@ -75,6 +75,9 @@ "chooseCategory":"Wähle eine Kategorie:", + "none":"keiner", + "reason":"Grund", + "deletedby":"Gelöscht von", "closedby":"Geschlossen von", "modalreason":"Was ist der Grund?", diff --git a/storage/database.json b/storage/database.json new file mode 100644 index 0000000..719dbd2 --- /dev/null +++ b/storage/database.json @@ -0,0 +1,12 @@ +[ + { + "category": "ticketStorage", + "key": "779742674932072469", + "value": 1 + }, + { + "category": "userTicketStorage", + "key": "1057318979082919936", + "value": "779742674932072469" + } +] \ No newline at end of file From a211cef1f6d969f0532a7504a6424d01b025f14e Mon Sep 17 00:00:00 2001 From: Jasper Date: Tue, 27 Dec 2022 17:36:52 +0100 Subject: [PATCH 3/6] Delete database.json --- storage/database.json | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 storage/database.json diff --git a/storage/database.json b/storage/database.json deleted file mode 100644 index 719dbd2..0000000 --- a/storage/database.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "category": "ticketStorage", - "key": "779742674932072469", - "value": 1 - }, - { - "category": "userTicketStorage", - "key": "1057318979082919936", - "value": "779742674932072469" - } -] \ No newline at end of file From 97d148955885f9c040771b7f40f6f008ca7910d4 Mon Sep 17 00:00:00 2001 From: Jasper Date: Tue, 27 Dec 2022 17:37:23 +0100 Subject: [PATCH 4/6] Delete .DS_Store --- storage/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 storage/.DS_Store diff --git a/storage/.DS_Store b/storage/.DS_Store deleted file mode 100644 index 9a48ed155612ac263b3278c6965b01a5b6f5b1de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKK~EDw6n+EMZb4*$Rv~)WSPw=>EJ93(F_fi7F)<)Zun1UoyF*#n?likwDiD&M z_2dumH+VJiW<2-{ycvIj9`)v%ooN7D5>JGfeaX!C=FNNa_I=x(=>P!H>-IQ+3IGZ= zj)@-ZItZWVtxdY5C5cF)HLBo18493VjW+Mt5Hk=naNZc;-);(Q*aHttIQIPpHOpld z&VI0Jt`mg0+*i`oow#r@sU($NW!>0f4I?zedZ3&BDjzK|=2|V?w3Z#(D5>dL=7px? zQ9lZBY>F;x&mGTZ4V~3JJBVTpF`=ZCR7o8^I2g}OjA@e-Q-@>P!PMOx*Y6!3rj$(f z&i%#Gj$8HEYe6N!ohOn$i7j}8N{7mv@~*6md}>wpT~%APrFwcV^Vq1K1#q@pCt5AJ!-8C)h&U-owLssRUe6=$37JSNADmtk1TC&qW1)tgc zvu31a^S6XWg{)BUbV#=}iDbz$t2C9$<`<+zfl-)&r?3n=un%wH9lVE+@CClX5BN=z zWQ5!xqhyjiAk*YAnIkVqiEI#4M0d5`@%58=$Tp5UykoaAZj@QICcU3@_NuZ%LH@>- zU$<{2wkJQ&oaSl&qi1dFc;*fM03Duh*YG`;c@>;(RmMHfT4Zje_pB4g`C3XHZ6?4m0GVgk*Ppw90SJVuk4m)I1DGbluaB8pHVuNXvxqg|7Jd5KMd zA{>akd=QzL$QufYvg7(%}o~>=g@v~OLwtv^ais90co Date: Tue, 27 Dec 2022 17:41:54 +0100 Subject: [PATCH 5/6] v3.1.0 push 3 --- .gitignore | 1 + storage/hello.txt | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 storage/hello.txt diff --git a/.gitignore b/.gitignore index b57bba5..f7290d8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ openticketdebug.txt developerChangelog.md storage/dynamicDB/ storage/slashcmdEnabled.txt +storage/database.json storage/.DS_Store .vscode/ livestatus.json diff --git a/storage/hello.txt b/storage/hello.txt new file mode 100644 index 0000000..11385e2 --- /dev/null +++ b/storage/hello.txt @@ -0,0 +1,3 @@ +This file is only here to make sure that this directory exists! + +I don't have any other use :) \ No newline at end of file From fc50a8e83f9226b36fa5c6ada67fb2ff93d255fd Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Sat, 31 Dec 2022 11:42:33 +0100 Subject: [PATCH 6/6] v3.1 last push --- config.json | 1 + core/checker.js | 40 +++++++- core/dynamicdatabase/dynamicfiles/database.js | 7 +- core/ticketActions/ticketCloser.js | 96 ++++++++++--------- 4 files changed, 95 insertions(+), 49 deletions(-) diff --git a/config.json b/config.json index c9e1e82..cab7717 100644 --- a/config.json +++ b/config.json @@ -105,6 +105,7 @@ "other":{ "enableTicketExplaination":true, "enableMaxTicketsWarning":true, + "customDropdownPlaceholder":{ "enable":false, "text":"Choose a ticket" diff --git a/core/checker.js b/core/checker.js index 9da940e..edc73db 100644 --- a/core/checker.js +++ b/core/checker.js @@ -311,10 +311,6 @@ exports.checker = async () => { checkHexColor(input.color,path+"/color") } - //ticket explaination & max tickets warning - checkType(input.other.enableTicketExplaination,"boolean",path+"/other/enableTicketExplaination") - checkType(input.other.enableMaxTicketsWarning,"boolean",path+"/other/enableMaxTicketsWarning") - //OPTIONS!!! var counter = 0 input.options.forEach((option) => {if (!configParser.optionExists(option)){counter++}}) @@ -328,6 +324,42 @@ exports.checker = async () => { } }) } + + //other + //ticket explaination & max tickets warning + if (typeof input.other != "object"){ + createError("'"+path+"/other' | this object doesn't exist!") + }else{ + checkType(input.other.enableTicketExplaination,"boolean",path+"/other/enableTicketExplaination") + checkType(input.other.enableMaxTicketsWarning,"boolean",path+"/other/enableMaxTicketsWarning") + + //customDropdownPlaceholder + if (typeof input.other.customDropdownPlaceholder != "object"){ + createError("'"+path+"/other/customDropdownPlaceholder' | this object doesn't exist!") + }else{ + checkType(input.other.customDropdownPlaceholder.enable,"boolean",path+"/other/customDropdownPlaceholder/enable") + checkType(input.other.customDropdownPlaceholder.text,"string",path+"/other/customDropdownPlaceholder/text") + if (input.other.customDropdownPlaceholder.enable && input.other.customDropdownPlaceholder.text.length < 1){createError("'"+path+"/other/customDropdownPlaceholder/text' | there is no placeholder text!")} + } + + //customCategoryText + if (typeof input.other.customCategoryText != "object"){ + createError("'"+path+"/other/customCategoryText' | this object doesn't exist!") + }else{ + checkType(input.other.customCategoryText.enable,"boolean",path+"/other/customCategoryText/enable") + checkType(input.other.customCategoryText.text,"string",path+"/other/customCategoryText/text") + if (input.other.customCategoryText.enable && input.other.customCategoryText.text.length < 1){createError("'"+path+"/other/customCategoryText/text' | there is no category text!")} + } + + //embedTitleURL + if (typeof input.other.embedTitleURL != "object"){ + createError("'"+path+"/other/embedTitleURL' | this object doesn't exist!") + }else{ + checkType(input.other.embedTitleURL.enable,"boolean",path+"/other/embedTitleURL/enable") + checkType(input.other.embedTitleURL.url,"string",path+"/other/embedTitleURL/text") + if (input.other.embedTitleURL.enable && input.other.embedTitleURL.url.length < 1){createError("'"+path+"/other/embedTitleURL/url' | there is no url!")} + } + } } //--------------------------| diff --git a/core/dynamicdatabase/dynamicfiles/database.js b/core/dynamicdatabase/dynamicfiles/database.js index f89955e..d0b167a 100644 --- a/core/dynamicdatabase/dynamicfiles/database.js +++ b/core/dynamicdatabase/dynamicfiles/database.js @@ -4,7 +4,12 @@ const location = "./storage/database.json" /**@returns {[{category:String, key:String, value:String}]}*/ function getData(){ - return JSON.parse(fs.readFileSync(location).toString()) + if (fs.existsSync(location)){ + return JSON.parse(fs.readFileSync(location).toString()) + }else{ + fs.writeFileSync(location,"[]") + return [] + } } /**@param {[{category:String, key:String, value:String}]} data*/ function setData(data){ diff --git a/core/ticketActions/ticketCloser.js b/core/ticketActions/ticketCloser.js index 8963ec6..ad1ff99 100755 --- a/core/ticketActions/ticketCloser.js +++ b/core/ticketActions/ticketCloser.js @@ -22,7 +22,6 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode,reason,nomessage) => const guild = channel.guild const user = member.user const chalk = await (await import("chalk")).default - const channelmessages = await channel.messages.fetch() const newReason = reason ? reason : l.messages.none @@ -31,9 +30,6 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode,reason,nomessage) => //FIX CHANNEL COULD BE CLOSED AFTER DELETE: if (pendingDelete.includes(channel.id)) return false - //remove ot bot from transcript - channelmessages.sweep((msgSweep) => {return msgSweep.author.id == client.user.id}) - /**@type {String}*/ const channelname = channel.name const ticketOpenerChannelName = channelname.split(prefix)[1] @@ -293,53 +289,65 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode,reason,nomessage) => } - if (enableTranscript == true && mode != "deletenotranscript"){ + const transcriptHandler = async () => { + if (enableTranscript == true && mode != "deletenotranscript"){ + //transcript messages + const transcriptReason = (mode == "close") ? "**"+l.messages.reason+":** "+newReason : "**"+l.messages.reason+":** "+l.messages.none + const closedByPrefix = (mode.startsWith("delete")) ? l.messages.deletedby : l.messages.closedby - const transcriptReason = (mode == "close") ? "**"+l.messages.reason+":** "+newReason : "**"+l.messages.reason+":** "+l.messages.none - const closedByPrefix = (mode.startsWith("delete")) ? l.messages.deletedby : l.messages.closedby + if (config.system.enable_transcript || config.system.enable_DM_transcript){ + const channelmessages = await channel.messages.fetch({cache:true}) + //remove ot bot from transcript + channelmessages.sweep((msgSweep) => {return msgSweep.author.id == client.user.id}) - if (config.system.enable_transcript || config.system.enable_DM_transcript){ - var fileattachment = await require("../transcript").createTranscript(channelmessages,channel) + var fileattachment = await require("../transcript").createTranscript(channelmessages,channel) - if (fileattachment == false){log("system","internal error: transcript is not created!");return} - } - - if (config.system.enable_transcript && !require("../api/api.json").disable.transcripts.server){ - const transcriptEmbed = new discord.EmbedBuilder() - .setColor(config.main_color) - .setTitle("📄 "+l.messages.newTranscriptTitle) - .setDescription(transcriptReason) - .setFooter({text:closedByPrefix+": "+user.tag+" | ticket: "+channelname,iconURL:user.displayAvatarURL()}) - - guild.channels.cache.find(c => c.id == config.system.transcript_channel).send({ - embeds:[transcriptEmbed], - files:[fileattachment] - }) - } + if (fileattachment == false){log("system","internal error: transcript is not created!");return} + } + + if (config.system.enable_transcript && !require("../api/api.json").disable.transcripts.server){ + const transcriptEmbed = new discord.EmbedBuilder() + .setColor(config.main_color) + .setTitle("📄 "+l.messages.newTranscriptTitle) + .setDescription(transcriptReason) + .setFooter({text:closedByPrefix+": "+user.tag+" | ticket: "+channelname,iconURL:user.displayAvatarURL()}) + + guild.channels.cache.find(c => c.id == config.system.transcript_channel).send({ + embeds:[transcriptEmbed], + files:[fileattachment] + }) + } - if (config.system.enable_DM_transcript && !require("../api/api.json").disable.transcripts.dm){ - const transcriptEmbed = new discord.EmbedBuilder() - .setColor(config.main_color) - .setTitle("📄 "+l.messages.newTranscriptTitle) - .setDescription(transcriptReason) - .setFooter({text:closedByPrefix+": "+user.tag+" | ticket: "+channelname,iconURL:user.displayAvatarURL()}) - - if (!isDatabaseError) ticketOpener.send({ - embeds:[transcriptEmbed], - files:[fileattachment] - }) + if (config.system.enable_DM_transcript && !require("../api/api.json").disable.transcripts.dm){ + const transcriptEmbed = new discord.EmbedBuilder() + .setColor(config.main_color) + .setTitle("📄 "+l.messages.newTranscriptTitle) + .setDescription(transcriptReason) + .setFooter({text:closedByPrefix+": "+user.tag+" | ticket: "+channelname,iconURL:user.displayAvatarURL()}) + + if (!isDatabaseError) ticketOpener.send({ + embeds:[transcriptEmbed], + files:[fileattachment] + }) + } } } + const deleteHandler = async () => { + if (deleteRequired){ + //const timer = () => {return new Promise((resolve,reject) => { + // setTimeout(() => {resolve(true)},7000) + //})} + //await timer() - if (deleteRequired){ - //const timer = () => {return new Promise((resolve,reject) => { - // setTimeout(() => {resolve(true)},7000) - //})} - //await timer() - - setTimeout(async () => { pendingDelete.shift() - await channel.delete() - },6000) + await channel.delete() + + //setTimeout(async () => { + // pendingDelete.shift() + // await channel.delete() + //},6000) + } } + await transcriptHandler() + deleteHandler() } \ No newline at end of file