diff --git a/.gitignore b/.gitignore index 4da0179..e485366 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ devConfig5.json openticketdebug.txt developerChangelog.md storage/dynamicDB/ -storage/.DS_Store \ No newline at end of file +storage/.DS_Store +.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index a5be7c1..525c76a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ make a ticket in our server to start! *if you translate, you will come in the credits* # 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-2.4.0%20stable-brightgreen.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/releases/tag/v2.4.0) [![npm](https://img.shields.io/badge/npm-external%20libraries%20needed-CB3837.svg?style=flat-square&logo=npm)](#packages) [![license](https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/blob/main/LICENSE) +[![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-2.5.0-brightgreen.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/releases/tag/v2.5.0) [![npm](https://img.shields.io/badge/npm-external%20libraries%20needed-CB3837.svg?style=flat-square&logo=npm)](#packages) [![license](https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/blob/main/LICENSE) This is an open-source discord ticket bot, you can configure it and it comes with cool features like transcripts & custom options! @@ -68,7 +68,7 @@ if there are any errors, you can open an **issue on github** or **contact me in ### config Our config documentation is moved to another file: -[click here to view](https://www.github.com/DJj123dj/open-ticket/wiki/config-v2.4.0) +[click here to view](https://www.github.com/DJj123dj/open-ticket/wiki/config-v2.5.0) ### intents & permissions In the discord developer portal in the "bot" panel you will find 3 switches under the title "Gateaway Intents". The following switches should always be turned on @@ -80,7 +80,7 @@ You can also configure your own permissions ## information -_v2.4.0 stable_ +_v2.5.0 stable_ changelog: [click here](https://www.github.com/DJj123dj/open-ticket/wiki/Changelog) diff --git a/commands/add.js b/commands/add.js index be5b848..e59c82e 100644 --- a/commands/add.js +++ b/commands/add.js @@ -22,18 +22,18 @@ module.exports = () => { msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") - msg.channel.permissionOverwrites.create(user.id, { VIEW_CHANNEL:true, ADD_REACTIONS:true,ATTACH_FILES:true, EMBED_LINKS:true, SEND_MESSAGES:true}) - msg.channel.send({embeds:[bot.errorLog.success(l.commands.userAddedTitle,l.commands.userAddedDescription.replace("{0}",user.tag))]}) + msg.channel.permissionOverwrites.create(user.id, { ViewChannel:true, AddReactions:true,AttachFiles:true, EmbedLinks:true, SendMessages:true}) + msg.channel.send({embeds:[bot.embeds.commands.addEmbed(user)]}) var loguser = msg.mentions.users.first() log("command","someone used the 'add' command",[{key:"user",value:msg.author.tag}]) log("system","user added to ticket",[{key:"user",value:msg.author.tag},{key:"ticket",value:msg.channel.name},{key:"added_user",value:loguser.tag}]) - const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] - const ticketData = require("../core/getoptions").getOptionsById("newT"+ticketId) + const ticketData = require("../core/getoptions").getOptionsById("OTnewT"+ticketId) APIEvents.onTicketAdd(msg.author,loguser,msg.channel,msg.guild,new Date(),{status:"open",name:msg.channel.name,ticketOptions:ticketData}) APIEvents.onCommand("add",permsChecker.command(msg.author.id,msg.guild.id),msg.author,msg.channel,msg.guild,new Date()) @@ -52,22 +52,20 @@ module.exports = () => { return } - interaction.deferReply() - interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") - interaction.channel.permissionOverwrites.create(user.id, { VIEW_CHANNEL:true, ADD_REACTIONS:true,ATTACH_FILES:true, EMBED_LINKS:true, SEND_MESSAGES:true}) - interaction.reply({embeds:[bot.errorLog.success(l.commands.userAddedTitle,l.commands.userAddedDescription.replace("{0}",user.tag))]}) + interaction.channel.permissionOverwrites.create(user.id, { ViewChannel:true, AddReactions:true,AttachFiles:true, EmbedLinks:true, SendMessages:true}) + interaction.reply({embeds:[bot.embeds.commands.addEmbed(user)]}) var loguser = user log("command","someone used the 'add' command",[{key:"user",value:interaction.user.tag}]) log("system","user added to ticket",[{key:"user",value:interaction.user.tag},{key:"ticket",value:interaction.channel.name},{key:"added_user",value:loguser.tag}]) - const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] - const ticketData = require("../core/getoptions").getOptionsById("newT"+ticketId) + const ticketData = require("../core/getoptions").getOptionsById("OTnewT"+ticketId) APIEvents.onTicketAdd(interaction.user,loguser,interaction.channel,interaction.guild,new Date(),{status:"open",name:interaction.channel.name,ticketOptions:ticketData}) APIEvents.onCommand("add",permsChecker.command(interaction.user.id,interaction.guild.id),interaction.user,interaction.channel,interaction.guild,new Date()) diff --git a/commands/close.js b/commands/close.js index 3c622f1..c117980 100644 --- a/commands/close.js +++ b/commands/close.js @@ -15,19 +15,22 @@ module.exports = () => { msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) - - const closebutton = new discord.ActionRowBuilder() - .addComponents([ - new discord.ButtonBuilder() - .setCustomId("closeTicketTrue1") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Secondary) - .setEmoji("🔒") - ]) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") - msg.channel.send({embeds:[bot.errorLog.success(l.commands.closeTitle,l.commands.closeDescription)],components:[closebutton]}) + msg.channel.send({embeds:[bot.embeds.commands.closeEmbed(msg.author)],components:[bot.buttons.close.closeCommandRow]}) + + var name = msg.channel.name + var prefix = "" + const tickets = config.options + tickets.forEach((ticket) => { + if (name.startsWith(ticket.channelprefix)){ + prefix = ticket.channelprefix + } + }) + + require("../core/ticketCloser").NEWcloseTicket(msg.member,msg.channel,prefix,"close",false,true) log("command","someone used the 'close' command",[{key:"user",value:msg.author.tag}]) APIEvents.onCommand("close",true,msg.author,msg.channel,msg.guild,new Date()) @@ -41,23 +44,26 @@ module.exports = () => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "close") return - interaction.deferReply() + //interaction.deferReply() interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) - - const closebutton = new discord.ActionRowBuilder() - .addComponents([ - new discord.ButtonBuilder() - .setCustomId("closeTicketTrue1") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Secondary) - .setEmoji("🔒") - ]) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") - interaction.reply({embeds:[bot.errorLog.success(l.commands.closeTitle,l.commands.closeDescription)],components:[closebutton]}) + interaction.reply({embeds:[bot.embeds.commands.closeEmbed(interaction.user)],components:[bot.buttons.close.closeCommandRow]}) + + var name = interaction.channel.name + var prefix = "" + const tickets = config.options + tickets.forEach((ticket) => { + if (name.startsWith(ticket.channelprefix)){ + prefix = ticket.channelprefix + } + }) + + require("../core/ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"close",false,true) log("command","someone used the 'close' command",[{key:"user",value:interaction.user.tag}]) APIEvents.onCommand("close",true,interaction.user,interaction.channel,interaction.guild,new Date()) diff --git a/commands/delete.js b/commands/delete.js index e3f1190..92a0571 100644 --- a/commands/delete.js +++ b/commands/delete.js @@ -20,19 +20,22 @@ module.exports = () => { msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) - - const closebutton = new discord.ActionRowBuilder() - .addComponents([ - new discord.ButtonBuilder() - .setCustomId("deleteTicketTrue") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Secondary) - .setEmoji("❌") - ]) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") - msg.channel.send({embeds:[bot.errorLog.success(l.commands.deleteTitle,l.commands.deleteDescription)],components:[closebutton]}) + msg.channel.send({embeds:[bot.embeds.commands.deleteEmbed(msg.author)]}) + + var name = msg.channel.name + var prefix = "" + const tickets = config.options + tickets.forEach((ticket) => { + if (name.startsWith(ticket.channelprefix)){ + prefix = ticket.channelprefix + } + }) + + require("../core/ticketCloser").NEWcloseTicket(msg.member,msg.channel,prefix,"delete",false,true) log("command","someone used the 'delete' command",[{key:"user",value:msg.author.tag}]) APIEvents.onCommand("delete",permsChecker.command(msg.author.id,msg.guild.id),msg.author,msg.channel,msg.guild,new Date()) @@ -45,7 +48,7 @@ module.exports = () => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "delete") return - interaction.deferReply() + //interaction.deferReply() if (!interaction.guild) return if (!permsChecker.command(interaction.user.id,interaction.guild.id)){ @@ -53,23 +56,26 @@ module.exports = () => { return } - interaction.channel.messages.fetchPinned().then(msglist => { + interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) - - const closebutton = new discord.ActionRowBuilder() - .addComponents([ - new discord.ButtonBuilder() - .setCustomId("deleteTicketTrue") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Secondary) - .setEmoji("❌") - ]) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") - interaction.reply({embeds:[bot.errorLog.success(l.commands.deleteTitle,l.commands.deleteDescription)],components:[closebutton]}) + interaction.reply({embeds:[bot.embeds.commands.deleteEmbed(interaction.user)]}) - log("command","someone used the 'close' command",[{key:"user",value:interaction.user.tag}]) + var name = interaction.channel.name + var prefix = "" + const tickets = config.options + tickets.forEach((ticket) => { + if (name.startsWith(ticket.channelprefix)){ + prefix = ticket.channelprefix + } + }) + + require("../core/ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"delete",false,true) + + log("command","someone used the 'delete' command",[{key:"user",value:interaction.user.tag}]) APIEvents.onCommand("delete",permsChecker.command(interaction.user.id,interaction.guild.id),interaction.user,interaction.channel,interaction.guild,new Date()) }) diff --git a/commands/help.js b/commands/help.js index 25df27e..cfdeaee 100644 --- a/commands/help.js +++ b/commands/help.js @@ -10,7 +10,7 @@ const APIEvents = require("../core/api/modules/events") module.exports = () => { const helpEmbed = new discord.EmbedBuilder() .setColor(config.main_color) - .setTitle(l.helpMenu.title) + .setTitle("❔ "+l.helpMenu.title) const prefix = config.prefix const header = config.system.ticket_channel ? l.helpMenu.header1.replace("{0}","<#"+config.system.ticket_channel+">") : l.helpMenu.header2 @@ -18,23 +18,25 @@ module.exports = () => { if (config.credits) helpEmbed.setFooter({text:"Open-Ticket by DJdj Development | view on github for source code",iconURL:"https://raw.githubusercontent.com/DJj123dj/open-ticket/main/logo.png"}) + var otherprefix = prefix.endsWith(" ") ? prefix.substring(0,prefix.length-1) : prefix client.on("messageCreate",msg => { if (!msg.content.startsWith(config.prefix)) return var args = msg.content.split(config.prefix) - if (!args[1]){ + if (msg.content == config.prefix || msg.content == config.prefix+" " || msg.content == otherprefix){ msg.channel.send({embeds:[helpEmbed]}) log("command","someone used the 'help' command",[{key:"user",value:msg.author.tag}]) APIEvents.onCommand("help",true,msg.author,msg.channel,msg.guild,new Date()) return } - if (!args[1].startsWith("close") && !args[1].startsWith("delete") && !args[1].startsWith("remove") && !args[1].startsWith("add") && !args[1].startsWith("msg") && !args[1].startsWith("remove") && !args[1].startsWith("rename") && !args[1].startsWith("reopen")){ - - msg.channel.send({embeds:[helpEmbed]}) - log("command","someone used the 'help' command",[{key:"user",value:msg.author.tag}]) - APIEvents.onCommand("help",true,msg.author,msg.channel,msg.guild,new Date()) + if (args[1]){ + if (!args[1].startsWith("close") && !args[1].startsWith("delete") && !args[1].startsWith("remove") && !args[1].startsWith("add") && !args[1].startsWith("msg") && !args[1].startsWith("remove") && !args[1].startsWith("rename") && !args[1].startsWith("reopen")){ + msg.channel.send({embeds:[helpEmbed]}) + log("command","someone used the 'help' command",[{key:"user",value:msg.author.tag}]) + APIEvents.onCommand("help",true,msg.author,msg.channel,msg.guild,new Date()) + } } }) diff --git a/commands/remove.js b/commands/remove.js index 29730b3..acba3c3 100644 --- a/commands/remove.js +++ b/commands/remove.js @@ -20,30 +20,28 @@ module.exports = () => { return } - interaction.deferReply() - msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") msg.channel.permissionOverwrites.delete(user.id) - msg.channel.send({embeds:[bot.errorLog.success(l.commands.userRemovedTitle,l.commands.userRemovedDescription.replace("{0}",user.tag))]}) + msg.channel.send({embeds:[bot.embeds.commands.removeEmbed(user)]}) var loguser = msg.mentions.users.first() log("command","someone used the 'remove' command",[{key:"user",value:msg.author.tag}]) log("system","user removed from ticket",[{key:"user",value:msg.author.tag},{key:"ticket",value:msg.channel.name},{key:"removed_user",value:loguser.tag}]) - const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] - const ticketData = require("../core/getoptions").getOptionsById("newT"+ticketId) + const ticketData = require("../core/getoptions").getOptionsById("OTnewT"+ticketId) APIEvents.onTicketRemove(msg.author,loguser,msg.channel,msg.guild,new Date(),{status:"open",name:msg.channel.name,ticketOptions:ticketData}) APIEvents.onCommand("remove",permsChecker.command(msg.author.id,msg.guild.id),msg.author,msg.channel,msg.guild,new Date()) }) }) - client.on("interactionCreate",(interaction) => { + client.on("interactionCreate",async (interaction) => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "remove") return const user = interaction.options.getUser("user") @@ -53,28 +51,24 @@ module.exports = () => { permsChecker.sendUserNoPerms(interaction.user) return } - - - interaction.channel.messages.fetchPinned().then(msglist => { + await interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") interaction.channel.permissionOverwrites.delete(user.id) - interaction.reply({embeds:[bot.errorLog.success(l.commands.userRemovedTitle,l.commands.userRemovedDescription.replace("{0}",user.tag))]}) + interaction.reply({embeds:[bot.embeds.commands.removeEmbed(user)]}) var loguser = user log("command","someone used the 'remove' command",[{key:"user",value:interaction.user.tag}]) log("system","user removed from ticket",[{key:"user",value:interaction.user.tag},{key:"ticket",value:interaction.channel.name},{key:"removed_user",value:loguser.tag}]) - const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] - const ticketData = require("../core/getoptions").getOptionsById("newT"+ticketId) + const ticketData = require("../core/getoptions").getOptionsById("OTnewT"+ticketId) APIEvents.onTicketRemove(interaction.user,loguser,interaction.channel,interaction.guild,new Date(),{status:"open",name:interaction.channel.name,ticketOptions:ticketData}) APIEvents.onCommand("remove",permsChecker.command(interaction.user.id,interaction.guild.id),interaction.user,interaction.channel,interaction.guild,new Date()) }) - - }) } \ No newline at end of file diff --git a/commands/rename.js b/commands/rename.js index e9ef4ef..b9da6d1 100644 --- a/commands/rename.js +++ b/commands/rename.js @@ -12,16 +12,17 @@ module.exports = () => { client.on("messageCreate",msg => { if (!msg.content.startsWith(config.prefix+"rename")) return + if (!msg.guild) return + if (!permsChecker.command(msg.author.id,msg.guild.id)){ + permsChecker.sendUserNoPerms(msg.author) + return + } + msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) - - if (!msg.guild) return - if (!permsChecker.command(msg.author.id,msg.guild.id)){ - permsChecker.sendUserNoPerms(msg.author) - return - } + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") var newname = msg.content.split(config.prefix+"rename")[1].substring(1) @@ -39,7 +40,7 @@ module.exports = () => { if (!prefix) prefix = "noprefix-" msg.channel.setName(prefix+newname) - msg.channel.send({embeds:[bot.errorLog.success(l.commands.renameTitle,l.commands.renameWarning)]}) + msg.channel.send({embeds:[bot.embeds.commands.renameEmbed(msg.author,prefix+newname)]}) log("command","someone used the 'rename' command",[{key:"user",value:msg.author.tag}]) log("system","ticket renamed",[{key:"user",value:msg.author.tag},{key:"ticket",value:name},{key:"newname",value:newname}]) @@ -53,18 +54,19 @@ module.exports = () => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "rename") return - interaction.deferReply() + if (!interaction.guild) return + if (!permsChecker.command(interaction.user.id,interaction.guild.id)){ + permsChecker.sendUserNoPerms(interaction.user) + return + } + + //interaction.deferReply() interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - - if (firstmsg == undefined || firstmsg.author.id != client.user.id)return interaction.reply({embeds:[bot.errorLog.notInATicket]}) - - if (!interaction.guild) return - if (!permsChecker.command(interaction.user.id,interaction.guild.id)){ - permsChecker.sendUserNoPerms(interaction.user) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") var newname = interaction.options.getString("name") var name = interaction.channel.name @@ -79,7 +81,7 @@ module.exports = () => { if (!prefix) prefix = "noprefix-" interaction.channel.setName(prefix+newname) - interaction.reply({embeds:[bot.errorLog.success(l.commands.renameTitle,l.commands.renameWarning)]}) + interaction.reply({embeds:[bot.embeds.commands.renameEmbed(interaction.user,prefix+newname)]}) log("command","someone used the 'rename' command",[{key:"user",value:interaction.user.tag}]) log("system","ticket renamed",[{key:"user",value:interaction.user.tag},{key:"ticket",value:name},{key:"newname",value:newname}]) diff --git a/commands/reopen.js b/commands/reopen.js index 20e6e6f..2e7ee04 100644 --- a/commands/reopen.js +++ b/commands/reopen.js @@ -9,25 +9,18 @@ const permsChecker = require("../core/utils/permisssionChecker") const APIEvents = require("../core/api/modules/events") module.exports = () => { - var reopenCommandBar = new discord.ActionRowBuilder() - .addComponents( - new discord.ButtonBuilder() - .setCustomId("reopenTicket1") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Secondary) - .setEmoji("🔓") - ) - client.on("messageCreate",msg => { if (!msg.content.startsWith(config.prefix+"reopen")) return msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") - msg.channel.send({embeds:[bot.errorLog.success(l.commands.reopenTitle,l.commands.reopenDescription)],components:[reopenCommandBar]}) + msg.channel.send({embeds:[bot.embeds.commands.reopenEmbed(msg.author)],components:[bot.buttons.close.openRowNormal]}) + require("../core/ticketReopener").reopenTicket(msg.guild,msg.channel,msg.author) log("command","someone used the 'reopen' command",[{key:"user",value:msg.author.tag}]) APIEvents.onCommand("reopen",true,msg.author,msg.channel,msg.guild,new Date()) @@ -39,19 +32,17 @@ module.exports = () => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "reopen") return - await interaction.deferReply() + //interaction.deferReply() interaction.channel.messages.fetchPinned().then(async msglist => { var firstmsg = msglist.last() + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) - - try { - await interaction.reply({embeds:[bot.errorLog.success(l.commands.reopenTitle,l.commands.reopenDescription)],components:[reopenCommandBar]}) - }catch{ - await interaction.editReply({embeds:[bot.errorLog.success(l.commands.reopenTitle,l.commands.reopenDescription)],components:[reopenCommandBar]}) - } + await interaction.reply({embeds:[bot.embeds.commands.reopenEmbed(interaction.user)],components:[bot.buttons.close.openRowNormal]}) + require("../core/ticketReopener").reopenTicket(interaction.guild,interaction.channel,interaction.user) log("command","someone used the 'reopen' command",[{key:"user",value:interaction.user.tag}]) APIEvents.onCommand("reopen",true,interaction.user,interaction.channel,interaction.guild,new Date()) diff --git a/config.json b/config.json index 8a8ccbf..d09e42b 100644 --- a/config.json +++ b/config.json @@ -79,7 +79,7 @@ "description":"You can click one of the buttons below!", "enableFooter":false, - "footer":"Open Ticket v2.4.0 - I'm a footer!", + "footer":"Open Ticket v2.5.0 - I'm a footer!", "enableThumbnail":false, "thumbnail":"https://www.example.com/catmemes/cat.png", diff --git a/core/api/modules/events.js b/core/api/modules/events.js index 7014799..150f2a5 100644 --- a/core/api/modules/events.js +++ b/core/api/modules/events.js @@ -49,14 +49,15 @@ exports.onTicketOpen = (user,channel,guild,date,ticketdata) => { * @param {discord.Guild} guild * @param {Date} date * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:Object|false}} ticketdata + * @param {String} reason */ -exports.onTicketClose = (user,channel,guild,date,ticketdata) => { +exports.onTicketClose = (user,channel,guild,date,ticketdata,reason) => { //system - bot.errorLog.log("api","ticket closed",[{key:"userid",value:user.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)}]) + bot.errorLog.log("api","ticket closed",[{key:"userid",value:user.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)},{key:"reason",value:reason}]) ticketCloseListeners.forEach((func) => { try { - func(user,channel,guild,date,ticketdata) + func(user,channel,guild,date,ticketdata,reason) }catch{} }) @@ -238,6 +239,16 @@ exports.onCommand = (type,hasPerms,user,channel,guild,date) => { * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:Object|false}} ticketdata */ +/** + * @callback TicketCloseEvent + * @param {discord.User} user + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:Object|false}} ticketdata + * @param {String} reason + */ + /** * @callback TranscriptCreationEvent * @param {discord.Message[]} messages @@ -290,7 +301,7 @@ const onTicketOpen = (callback) => { ticketOpenListeners.push(callback) } -/**@param {TicketActionEvent} callback */ +/**@param {TicketCloseEvent} callback */ const onTicketClose = (callback) => { ticketCloseListeners.push(callback) } diff --git a/core/checker.js b/core/checker.js index 0a2e6b2..64a69ef 100644 --- a/core/checker.js +++ b/core/checker.js @@ -41,7 +41,7 @@ exports.checker = async () => { } /**@param {String} value */ const checkToken = (value) => { - if (value.includes(" ") || value.length < 40 || value.length > 90){ + if (value.includes(" ") || value.length < 40){ createError("'auth_token' | your token is invalid") } } diff --git a/core/dynamicdatabase/storage.js b/core/dynamicdatabase/storage.js index 7fa0482..80ad75d 100644 --- a/core/dynamicdatabase/storage.js +++ b/core/dynamicdatabase/storage.js @@ -10,24 +10,4 @@ try { process.exit(1) } -module.exports = db - - -/** ============================= - ** NOT READY YET - ** must be dynamic - ** =============================*/ -//const LocalStorage = require("node-localstorage") -// -//const ticketStorage = new LocalStorage.LocalStorage("./storage/tickets") -//exports.ticketStorage = ticketStorage -// -//const userTicketStorage = new LocalStorage.LocalStorage("./storage/userTickets") -//exports.userTicketStorage = userTicketStorage -// -//const transcriptStorage = new LocalStorage.LocalStorage("./storage/transcripts") -//exports.transcriptStorage = transcriptStorage - -//const ticketNumberStorage = new LocalStorage.LocalStorage("./storage/ticketNumbers") -//exports.ticketNumberStorage = ticketNumberStorage - +module.exports = db \ No newline at end of file diff --git a/core/errorLogSystem.js b/core/errorLogSystem.js index 169f8b7..b2ab1ff 100644 --- a/core/errorLogSystem.js +++ b/core/errorLogSystem.js @@ -12,14 +12,19 @@ const c = discord.Colors exports.noPermsMessage = new embed() .setColor(c.Red) - .setTitle(":x: "+l.errors.noPermsTitle+" :x:") + .setTitle(":x: "+l.errors.noPermsTitle) .setDescription(l.errors.noPermsDescription) +exports.noPermsDelete = new embed() + .setColor(c.Red) + .setTitle(":x: "+l.errors.noPermsTitle) + .setDescription(l.errors.noPermsDelete) + /**@param {String} message */ exports.invalidArgsMessage = (message) => { var x = new embed() .setColor(c.Red) - .setTitle(":x: "+l.errors.missingArgsTitle+" :x:") + .setTitle(":x: "+l.errors.missingArgsTitle) .setDescription(message) return x @@ -29,7 +34,7 @@ exports.invalidArgsMessage = (message) => { exports.serverError = (message) => { var x = new embed() .setColor(c.Orange) - .setTitle(":warning: "+l.errors.boterror+" :warning:") + .setTitle(":warning: "+l.errors.boterror) .setDescription(message) return x @@ -39,14 +44,14 @@ exports.serverError = (message) => { exports.invalidIdChooseFromList = (list) => { var x = new embed() .setColor(c.Red) - .setTitle(":x: "+l.errors.chooseFromListTitle+" :x:") + .setTitle(":x: "+l.errors.chooseFromListTitle) .setDescription(l.errors.chooseFromListDescription+"\n`"+list.join("`\n`")+"`") return x } exports.notInATicket = new embed() .setColor(c.Red) - .setTitle(":x: "+l.errors.notInTicketTitle+" :x:") + .setTitle(":x: "+l.errors.notInTicketTitle) .setDescription(l.errors.notInTicketDescription) @@ -54,7 +59,7 @@ exports.notInATicket = new embed() exports.success = (title,message) => { var x = new embed() .setColor(config.main_color) - .setTitle(":white_check_mark: "+title+" :white_check_mark:") + .setTitle(":white_check_mark: "+title) .setDescription(message) return x @@ -64,7 +69,7 @@ exports.success = (title,message) => { exports.warning = (title,message) => { var x = new embed() .setColor(c.Orange) - .setTitle(":warning: "+title+" :warning:") + .setTitle(":warning: "+title) .setDescription(message) return x @@ -74,7 +79,7 @@ exports.warning = (title,message) => { exports.custom = (title,message,emoji,color) => { var x = new embed() .setColor(color) - .setTitle(emoji+" "+title+" "+emoji) + .setTitle(emoji+" "+title) .setDescription(message) return x diff --git a/core/getoptions.js b/core/getoptions.js index ada3a01..b691a67 100644 --- a/core/getoptions.js +++ b/core/getoptions.js @@ -7,7 +7,7 @@ const config = bot.config */ exports.getTicketValue = (index,value) => { if (value == "id"){ - return "newT"+config.options[index][value] + return "OTnewT"+config.options[index][value] } return config.options[index][value] } @@ -35,7 +35,7 @@ exports.getRoleValue = (index,value) => { var result = [] config.options.forEach((o) => { if (value == "id"){ - result.push("newT"+o[value]) + result.push("OTnewT"+o[value]) }else{ result.push(o[value]) } @@ -90,7 +90,7 @@ class TicketOptions { exports.getOptionsById = (id) => { var result = false config.options.forEach((option) => { - if ("newT"+option.id == id){ + if ("OTnewT"+option.id == id){ result = option } }) diff --git a/core/interactionHandlers/buttons/close.js b/core/interactionHandlers/buttons/close.js new file mode 100644 index 0000000..1a8a445 --- /dev/null +++ b/core/interactionHandlers/buttons/close.js @@ -0,0 +1,78 @@ +const discord = require('discord.js') +const bot = require('../../../index') +const client = bot.client +const config = bot.config +const l = bot.language +const log = bot.errorLog.log + +const getconfigoptions = require("../../getoptions") +const hiddendata = bot.hiddenData +const embed = discord.EmbedBuilder +const mc = config.main_color + +const button = discord.ButtonBuilder +const arb = discord.ActionRowBuilder +const bs = discord.ButtonStyle + + +exports.closeCommandRow = new arb() + .addComponents( + new button() + .setCustomId("OTdeleteTicket1") + .setDisabled(false) + .setStyle(bs.Danger) + .setLabel(l.buttons.delete) + .setEmoji("✖️") + ) + .addComponents( + new button() + .setCustomId("OTsendTranscript") + .setDisabled(false) + .setStyle(bs.Secondary) + .setLabel(l.buttons.sendTranscript) + .setEmoji("📄") + ) + .addComponents( + new button() + .setCustomId("OTreopenTicket") + .setDisabled(false) + .setStyle(bs.Success) + .setLabel(l.buttons.reopen) + .setEmoji("✔") + ) + +exports.openRowNormal = new arb() + .addComponents( + new button() + .setCustomId("OTcloseTicket") + .setDisabled(false) + .setStyle(bs.Secondary) + .setLabel(l.buttons.close) + .setEmoji("🔒") + ) + .addComponents( + new button() + .setCustomId("OTdeleteTicket") + .setDisabled(false) + .setStyle(bs.Danger) + .setLabel(l.buttons.delete) + .setEmoji("✖️") + ) + +exports.openRowDisabled = new arb() + .addComponents( + new button() + .setCustomId("OTcloseTicket") + .setDisabled(true) + .setStyle(bs.Secondary) + .setLabel(l.buttons.close) + .setEmoji("🔒") + ) + .addComponents( + new button() + .setCustomId("OTdeleteTicket") + .setDisabled(true) + .setStyle(bs.Danger) + .setLabel(l.buttons.delete) + .setEmoji("✖️") + ) \ No newline at end of file diff --git a/core/interactionHandlers/buttons/firstmsg.js b/core/interactionHandlers/buttons/firstmsg.js new file mode 100644 index 0000000..53edd15 --- /dev/null +++ b/core/interactionHandlers/buttons/firstmsg.js @@ -0,0 +1,52 @@ +const discord = require('discord.js') +const bot = require('../../../index') +const client = bot.client +const config = bot.config +const l = bot.language +const log = bot.errorLog.log + +const getconfigoptions = require("../../getoptions") +const hiddendata = bot.hiddenData +const embed = discord.EmbedBuilder +const mc = config.main_color + +const button = discord.ButtonBuilder +const arb = discord.ActionRowBuilder +const bs = discord.ButtonStyle + + +exports.firstmsgRowNormal = new arb() + .addComponents( + new button() + .setCustomId("OTcloseTicket") + .setDisabled(false) + .setStyle(bs.Secondary) + .setLabel(l.buttons.close) + .setEmoji("🔒") + ) + .addComponents( + new button() + .setCustomId("OTdeleteTicket") + .setDisabled(false) + .setStyle(bs.Danger) + .setLabel(l.buttons.delete) + .setEmoji("✖️") + ) + +exports.firstmsgRowDisabled = new arb() + .addComponents( + new button() + .setCustomId("OTcloseTicket") + .setDisabled(true) + .setStyle(bs.Secondary) + .setLabel(l.buttons.close) + .setEmoji("🔒") + ) + .addComponents( + new button() + .setCustomId("OTdeleteTicket") + .setDisabled(true) + .setStyle(bs.Danger) + .setLabel(l.buttons.delete) + .setEmoji("✖️") + ) \ No newline at end of file diff --git a/core/interactionHandlers/buttons/verifyBars.js b/core/interactionHandlers/buttons/verifyBars.js new file mode 100644 index 0000000..7d1b864 --- /dev/null +++ b/core/interactionHandlers/buttons/verifyBars.js @@ -0,0 +1,63 @@ +const discord = require('discord.js') +const bot = require('../../../index') +const client = bot.client +const config = bot.config +const l = bot.language +const log = bot.errorLog.log + +const getconfigoptions = require("../../getoptions") +const hiddendata = bot.hiddenData +const embed = discord.EmbedBuilder +const mc = config.main_color + +const button = discord.ButtonBuilder +const arb = discord.ActionRowBuilder +const bs = discord.ButtonStyle + +exports.closeVerifyBar = new arb() + .addComponents( + new button() + .setCustomId("OTcloseTicketTrue") + .setDisabled(false) + .setStyle(bs.Secondary) + .setEmoji("✅") + ) + .addComponents( + new button() + .setCustomId("OTcloseTicketFalse") + .setDisabled(false) + .setStyle(bs.Secondary) + .setEmoji("❌") + ) + +exports.deleteVerifyBar = new arb() + .addComponents( + new button() + .setCustomId("OTdeleteTicketTrue") + .setDisabled(false) + .setStyle(bs.Secondary) + .setEmoji("✅") + ) + .addComponents( + new button() + .setCustomId("OTdeleteTicketFalse") + .setDisabled(false) + .setStyle(bs.Secondary) + .setEmoji("❌") + ) + +exports.delete1VerifyBar = new arb() + .addComponents( + new button() + .setCustomId("OTdeleteTicketTrue1") + .setDisabled(false) + .setStyle(bs.Secondary) + .setEmoji("✅") + ) + .addComponents( + new button() + .setCustomId("OTdeleteTicketFalse1") + .setDisabled(false) + .setStyle(bs.Secondary) + .setEmoji("❌") + ) \ No newline at end of file diff --git a/core/interactionHandlers/embeds/commands.js b/core/interactionHandlers/embeds/commands.js new file mode 100644 index 0000000..425b093 --- /dev/null +++ b/core/interactionHandlers/embeds/commands.js @@ -0,0 +1,84 @@ +const discord = require('discord.js') +const bot = require('../../../index') +const client = bot.client +const config = bot.config +const l = bot.language +const log = bot.errorLog.log + +const getconfigoptions = require("../../getoptions") +const hiddendata = bot.hiddenData +const embed = discord.EmbedBuilder +const mc = config.main_color + +/** + * + * @param {discord.User} addedUser + * @returns {discord.EmbedBuilder} + */ +exports.addEmbed = (addedUser) => { + return new embed() + .setTitle("⬆️ "+l.commands.userAddedTitle.replace("{0}",addedUser.username)) + .setColor(mc) + .setFooter({text:addedUser.tag,iconURL:addedUser.displayAvatarURL()}) +} + +/** + * + * @param {discord.User} removedUser + * @returns {discord.EmbedBuilder} + */ +exports.removeEmbed = (removedUser) => { + return new embed() + .setTitle("⬇️ "+l.commands.userRemovedTitle.replace("{0}",removedUser.username)) + .setColor(mc) + .setFooter({text:removedUser.tag,iconURL:removedUser.displayAvatarURL()}) +} + +/** + * + * @param {discord.User} closer + * @returns {discord.EmbedBuilder} + */ +exports.closeEmbed = (closer) => { + return new embed() + .setTitle("🔒 "+l.commands.closeTitle) + .setColor(mc) + .setFooter({text:closer.tag,iconURL:closer.displayAvatarURL()}) +} + +/** + * + * @param {discord.User} deleter + * @returns {discord.EmbedBuilder} + */ +exports.deleteEmbed = (deleter) => { + return new embed() + .setTitle("❌ "+l.commands.deleteTitle) + .setColor(mc) + .setFooter({text:deleter.tag,iconURL:deleter.displayAvatarURL()}) +} + +/** + * + * @param {discord.User} renamer + * @param {String} newname + * @returns {discord.EmbedBuilder} + */ +exports.renameEmbed = (renamer,newname) => { + return new embed() + .setTitle("🔄 "+l.commands.renameTitle.replace("{0}",newname)) + .setColor(mc) + .setFooter({text:renamer.tag,iconURL:renamer.displayAvatarURL()}) +} + +/** + * + * @param {discord.User} reopener + * @returns {discord.EmbedBuilder} + */ + exports.reopenEmbed = (reopener) => { + return new embed() + .setTitle("🔓 "+l.commands.reopenTitle) + .setColor(mc) + .setFooter({text:reopener.tag,iconURL:reopener.displayAvatarURL()}) +} \ No newline at end of file diff --git a/core/interactionHandlers/handlers/accepted/closing.js b/core/interactionHandlers/handlers/accepted/closing.js new file mode 100644 index 0000000..0fa09ad --- /dev/null +++ b/core/interactionHandlers/handlers/accepted/closing.js @@ -0,0 +1,60 @@ +const discord = require('discord.js') +const bot = require('../../../../index') +const client = bot.client +const config = bot.config +const l = bot.language +const log = bot.errorLog.log + +const getconfigoptions = require("../../../getoptions") +const permissionChecker = require("../../../utils/permisssionChecker") +const storage = bot.storage +const hiddendata = bot.hiddenData +const embed = discord.EmbedBuilder +const mc = config.main_color + +const button = discord.ButtonBuilder +const arb = discord.ActionRowBuilder +const bs = discord.ButtonStyle + +module.exports = () => { + //CLOSE + var closeTicketButtonChecker = false + client.on("interactionCreate",async interaction => { + if (!interaction.isButton()) return + if (interaction.customId != "OTcloseTicketTrue") return + + interaction.deferUpdate() + + if (closeTicketButtonChecker == true) return + closeTicketButtonChecker = true + + const firstcomponents = interaction.message.components + + if (config.system.closeMode == "adminonly"){ + if (!permissionChecker.command(interaction.user.id,interaction.guild.id)){ + if (!permissionChecker.sendUserNoPerms(interaction.user)){ + permissionChecker.sendChannelNoPerms(interaction.channel) + } + interaction.message.edit({components:firstcomponents}) + } + } + + interaction.message.edit({components:[bot.buttons.close.openRowDisabled]}) + + /** + * @type {String} + */ + const name = interaction.channel.name + var prefix = "" + const tickets = config.options + tickets.forEach((ticket) => { + if (name.startsWith(ticket.channelprefix)){ + prefix = ticket.channelprefix + } + }) + + interaction.channel.send({embeds:[bot.embeds.commands.closeEmbed(interaction.user)],components:[bot.buttons.close.closeCommandRow]}) + await require("../../../ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"close",false,true) + closeTicketButtonChecker = false + }) +} \ No newline at end of file diff --git a/core/interactionHandlers/handlers/accepted/reopening.js b/core/interactionHandlers/handlers/accepted/reopening.js new file mode 100644 index 0000000..4b404b5 --- /dev/null +++ b/core/interactionHandlers/handlers/accepted/reopening.js @@ -0,0 +1,29 @@ +const discord = require('discord.js') +const bot = require('../../../../index') +const client = bot.client +const config = bot.config +const l = bot.language +const log = bot.errorLog.log + +const getconfigoptions = require("../../../getoptions") +const permissionChecker = require("../../../utils/permisssionChecker") +const storage = bot.storage +const hiddendata = bot.hiddenData +const embed = discord.EmbedBuilder +const mc = config.main_color + +const button = discord.ButtonBuilder +const arb = discord.ActionRowBuilder +const bs = discord.ButtonStyle + +module.exports = () => { + //REOPEN + client.on("interactionCreate",(interaction) => { + if (!interaction.isButton()) return + if (interaction.customId != "OTreopenTicket") return + + interaction.deferUpdate() + interaction.message.edit({embeds:[bot.embeds.commands.reopenEmbed(interaction.user)],components:[bot.buttons.close.openRowNormal]}) + require("../../../ticketReopener").reopenTicket(interaction.guild,interaction.channel,interaction.user) + }) +} \ No newline at end of file diff --git a/core/interactionHandlers/handlers/firstmsg.js b/core/interactionHandlers/handlers/firstmsg.js new file mode 100644 index 0000000..bf340db --- /dev/null +++ b/core/interactionHandlers/handlers/firstmsg.js @@ -0,0 +1,21 @@ +const discord = require('discord.js') +const bot = require('../../../index') +const client = bot.client +const config = bot.config +const l = bot.language +const log = bot.errorLog.log + +const getconfigoptions = require("../../getoptions") +const storage = bot.storage +const hiddendata = bot.hiddenData +const embed = discord.EmbedBuilder +const mc = config.main_color + +const button = discord.ButtonBuilder +const arb = discord.ActionRowBuilder +const bs = discord.ButtonStyle + + +module.exports = () => { + +} \ No newline at end of file diff --git a/core/interactionHandlers/handlers/handlers.js b/core/interactionHandlers/handlers/handlers.js new file mode 100644 index 0000000..b3d1ac7 --- /dev/null +++ b/core/interactionHandlers/handlers/handlers.js @@ -0,0 +1,9 @@ +module.exports = () => { + require("./firstmsg")() + require("./sendTranscript")() + require("./verifyBars")() + + //accepted + require("./accepted/closing")() + require("./accepted/reopening")() +} \ No newline at end of file diff --git a/core/interactionHandlers/handlers/sendTranscript.js b/core/interactionHandlers/handlers/sendTranscript.js new file mode 100644 index 0000000..6321979 --- /dev/null +++ b/core/interactionHandlers/handlers/sendTranscript.js @@ -0,0 +1,42 @@ +const discord = require('discord.js') +const bot = require('../../../index') +const client = bot.client +const config = bot.config +const l = bot.language +const log = bot.errorLog.log + +const getconfigoptions = require("../../getoptions") +const storage = bot.storage +const hiddendata = bot.hiddenData +const embed = discord.EmbedBuilder +const mc = config.main_color + +const button = discord.ButtonBuilder +const arb = discord.ActionRowBuilder +const bs = discord.ButtonStyle + + +module.exports = () => { + client.on("interactionCreate",async (interaction) => { + if (!interaction.isButton()) return + if (interaction.customId != "OTsendTranscript") return + + interaction.deferUpdate() + + const channelmessages = await interaction.channel.messages.fetch() + + channelmessages.sweep((msgSweep) => { + return msgSweep.author.id == client.user.id + }) + + var fileattachment = await require("../../transcript").createTranscript(channelmessages,interaction.channel) + + if (fileattachment == false){ + log("system","internal error: transcript is not created!") + interaction.channel.send({embeds:[bot.errorLog.serverError(l.errors.somethingWentWrongTranscript)]}) + return + } + + interaction.channel.send({content:"**"+l.messages.hereIsTheTranscript+"**",files:[fileattachment]}) + }) +} \ No newline at end of file diff --git a/core/interactionHandlers/handlers/verifyBars.js b/core/interactionHandlers/handlers/verifyBars.js new file mode 100644 index 0000000..941a3cd --- /dev/null +++ b/core/interactionHandlers/handlers/verifyBars.js @@ -0,0 +1,35 @@ +const discord = require('discord.js') +const bot = require('../../../index') +const client = bot.client +const config = bot.config +const l = bot.language +const log = bot.errorLog.log + +const getconfigoptions = require("../../getoptions") +const storage = bot.storage +const hiddendata = bot.hiddenData +const embed = discord.EmbedBuilder +const mc = config.main_color + +const button = discord.ButtonBuilder +const arb = discord.ActionRowBuilder +const bs = discord.ButtonStyle + +module.exports = () => { + //CLOSE + client.on("interactionCreate",interaction => { + if (!interaction.isButton()) return + if (interaction.customId != "OTcloseTicket") return + + interaction.deferUpdate() + interaction.message.edit({components:[bot.buttons.verifybars.closeVerifyBar]}) + + }) + client.on("interactionCreate",interaction => { + if (!interaction.isButton()) return + if (interaction.customId != "OTcloseTicketFalse") return + + interaction.deferUpdate() + interaction.message.edit({components:[bot.buttons.close.openRowNormal]}) + }) +} \ No newline at end of file diff --git a/core/slashSystem/slashEnable.js b/core/slashSystem/slashEnable.js index 2fa1510..ee86197 100644 --- a/core/slashSystem/slashEnable.js +++ b/core/slashSystem/slashEnable.js @@ -29,10 +29,10 @@ module.exports = async () => { var readystats = 0 - process.stdout.write("[status] there are "+chalk.blue("0 out of 10")+" commands ready! (this can take up to 40 seconds)") + //process.stdout.write("[status] there are "+chalk.blue("0 out of 10")+" commands ready! (this can take up to 40 seconds)") setInterval(() => { process.stdout.cursorTo(0) - process.stdout.write("[status] there are "+chalk.blue(readystats+" out of 9")+" commands ready! (this can take up to 40 seconds)") + process.stdout.write("[status] there are "+chalk.blue(readystats+" out of 10")+" commands ready! (this can take up to 40 seconds)") if (readystats >= 10){ console.log(chalk.green("\nready!")) console.log(chalk.bgBlue("you can now start the bot with 'npm start'!")) diff --git a/core/ticketCloser.js b/core/ticketCloser.js index 9654066..8ac3292 100755 --- a/core/ticketCloser.js +++ b/core/ticketCloser.js @@ -38,13 +38,17 @@ exports.runThis = () => { * @param {discord.TextChannel} channel * @param {String} prefix * @param {"delete"|"close"|"deletenotranscript"} mode + * @param {Boolean} nomessage + * @param {String} reason only when closing, not when deleting! */ -exports.NEWcloseTicket = async (member,channel,prefix,mode) => { +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 : "none" + //start code //remove ot bot from transcript @@ -80,7 +84,9 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { //start delete proccess deleteRequired = true - await channel.send({content:"**"+l.messages.gettingdeleted+"**"}) + if (!nomessage){ + await channel.send({content:"**"+l.messages.gettingdeleted+"**"}) + } log("system","deleted a ticket",[{key:"user",value:user.tag},{key:"ticket",value:channel.name}]) if (!isDatabaseError) storage.set("ticketStorage",getuserID,Number(storage.get("ticketStorage",getuserID)) - 1) @@ -92,7 +98,7 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] - const ticketData = require("./getoptions").getOptionsById("newT"+ticketId) + const ticketData = require("./getoptions").getOptionsById("OTnewT"+ticketId) require("./api/modules/events").onTicketDelete(user,channel,guild,new Date(),{name:channel.name,status:"deleted",ticketOptions:ticketData}) @@ -159,7 +165,7 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] - const ticketData = require("./getoptions").getOptionsById("newT"+ticketId) + const ticketData = require("./getoptions").getOptionsById("OTnewT"+ticketId) if (!ticketData) return @@ -188,38 +194,40 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { channel.permissionOverwrites.set(permissionArray) - //message - var closeButtonRow = new discord.ActionRowBuilder() - .addComponents( - new discord.ButtonBuilder() - .setCustomId("deleteTicket1") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Danger) - .setLabel(l.buttons.delete) - .setEmoji("✖️") - ) - .addComponents( - new discord.ButtonBuilder() - .setCustomId("sendTranscript") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Secondary) - .setLabel(l.buttons.sendTranscript) - .setEmoji("📄") - ) - .addComponents( - new discord.ButtonBuilder() - .setCustomId("reopenTicket") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Success) - .setLabel(l.buttons.reopen) - .setEmoji("✔") - ) - - const embed = new discord.EmbedBuilder() - .setColor(config.main_color) - .setTitle(":lock: "+l.messages.closedTitle+" :lock:") - .setDescription(l.messages.closedDescription) - channel.send({embeds:[embed],components:[closeButtonRow]}) + if (!nomessage){ + //message + var closeButtonRow = new discord.ActionRowBuilder() + .addComponents( + new discord.ButtonBuilder() + .setCustomId("OTdeleteTicket1") + .setDisabled(false) + .setStyle(discord.ButtonStyle.Danger) + .setLabel(l.buttons.delete) + .setEmoji("✖️") + ) + .addComponents( + new discord.ButtonBuilder() + .setCustomId("OTsendTranscript") + .setDisabled(false) + .setStyle(discord.ButtonStyle.Secondary) + .setLabel(l.buttons.sendTranscript) + .setEmoji("📄") + ) + .addComponents( + new discord.ButtonBuilder() + .setCustomId("OTreopenTicket") + .setDisabled(false) + .setStyle(discord.ButtonStyle.Success) + .setLabel(l.buttons.reopen) + .setEmoji("✔") + ) + + const embed = new discord.EmbedBuilder() + .setColor(config.main_color) + .setTitle(":lock: "+l.messages.closedTitle+" :lock:") + .setDescription(l.messages.closedDescription) + channel.send({embeds:[embed],components:[closeButtonRow]}) + } log("system","closed a ticket",[{key:"user",value:user.tag},{key:"ticket",value:channel.name}]) @@ -230,9 +238,9 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] - const ticketData = require("./getoptions").getOptionsById("newT"+ticketId) + const ticketData = require("./getoptions").getOptionsById("OTnewT"+ticketId) - require("./api/modules/events").onTicketClose(user,channel,guild,new Date(),{name:channel.name,status:"closed",ticketOptions:ticketData}) + require("./api/modules/events").onTicketClose(user,channel,guild,new Date(),{name:channel.name,status:"closed",ticketOptions:ticketData},newReason) const id = firstmsg.embeds[0].author.name @@ -240,7 +248,7 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { try{ if (config.system.enable_DM_Messages){ - member.send({embeds:[bot.errorLog.custom(l.messages.closedTicketDmTitle,l.messages.closedTicketDmDescription,":ticket:",config.main_color)]}) + member.send({embeds:[bot.errorLog.custom(l.messages.closedTicketDmTitle,l.messages.closedTicketDmDescription+"\n\n**reason:** "+newReason,":ticket:",config.main_color)]}) } } catch{log("system","can't send DM to member, member doesn't allow dm's")} @@ -259,7 +267,9 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { //start delete proccess enableTranscript = false deleteRequired = true - channel.send({content:"**"+l.messages.gettingdeleted+"**"}) + if (!nomessage){ + await channel.send({content:"**"+l.messages.gettingdeleted+"**"}) + } log("system","deleted a ticket",[{key:"user",value:user.tag},{key:"ticket",value:channel.name}]) if (!isDatabaseError) storage.set("ticketStorage",getuserID,Number(storage.get("ticketStorage",getuserID)) - 1) @@ -271,7 +281,7 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] - const ticketData = require("./getoptions").getOptionsById("newT"+ticketId) + const ticketData = require("./getoptions").getOptionsById("OTnewT"+ticketId) require("./api/modules/events").onTicketDelete(user,channel,guild,new Date(),{name:channel.name,status:"deleted",ticketOptions:ticketData}) @@ -291,6 +301,8 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { if (enableTranscript == true && mode != "deletenotranscript"){ + const transcriptReason = (mode == "close") ? "**reason:** "+newReason : "**reason:** none" + if (config.system.enable_transcript || config.system.enable_DM_transcript){ var fileattachment = await require("./transcript").createTranscript(channelmessages,channel) @@ -300,10 +312,9 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { if (config.system.enable_transcript){ const transcriptEmbed = new discord.EmbedBuilder() .setColor(config.main_color) - .setTitle(l.messages.newTranscriptTitle) - .setAuthor({name:user.username,iconURL:user.displayAvatarURL({format:"png"})}) - .setDescription(l.messages.newTranscriptDescription) - .setFooter({text:"ticket: "+channelname}) + .setTitle("📄 "+l.messages.newTranscriptTitle) + .setDescription(transcriptReason) + .setFooter({text:"closed by: "+user.tag+" | ticket: "+channelname,iconURL:user.displayAvatarURL()}) guild.channels.cache.find(c => c.id == config.system.transcript_channel).send({ embeds:[transcriptEmbed], @@ -314,9 +325,9 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode) => { if (config.system.enable_DM_transcript){ const transcriptEmbed = new discord.EmbedBuilder() .setColor(config.main_color) - .setTitle(l.messages.newTranscriptTitle) - .setDescription(l.messages.newTranscriptDescription) - .setFooter({text:"ticket: "+channelname}) + .setTitle("📄 "+l.messages.newTranscriptTitle) + .setDescription(transcriptReason) + .setFooter({text:"closed by: "+user.tag+" | ticket: "+channelname,iconURL:user.displayAvatarURL()}) if (!isDatabaseError) ticketOpener.send({ embeds:[transcriptEmbed], diff --git a/core/ticketOpener.js b/core/ticketOpener.js index dce1fbb..d17f973 100755 --- a/core/ticketOpener.js +++ b/core/ticketOpener.js @@ -9,35 +9,19 @@ const getconfigoptions = require("./getoptions") const storage = bot.storage module.exports = () => { - var closeButton = new discord.ActionRowBuilder() - .addComponents( - new discord.ButtonBuilder() - .setCustomId("closeTicket") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Secondary) - .setLabel(l.buttons.close) - .setEmoji("🔒") - ) - .addComponents( - new discord.ButtonBuilder() - .setCustomId("deleteTicket") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Danger) - .setLabel(l.buttons.delete) - .setEmoji("✖️") - ) + var closeButton = bot.buttons.firstmsg.firstmsgRowNormal //ticket button click / create ticket client.on("interactionCreate",(interaction) => { if (interaction.isChatInputCommand() && (interaction.commandName == "new" || interaction.commandName == "ticket")){ - var customId = "newT"+interaction.options.getString("type") + var customId = "OTnewT"+interaction.options.getString("type") }else if (interaction.isButton()){ var customId = interaction.customId }else return if (interaction.isButton()){ - if (interaction.customId.startsWith("newT")){ - const optionid = interaction.customId.split("newT")[1] + if (interaction.customId.startsWith("OTnewT")){ + const optionid = interaction.customId.split("OTnewT")[1] if (!optionid){ interaction.reply({embeds:[bot.errorLog.serverError(l.errors.ticketDoesntExist)]}) return @@ -173,13 +157,19 @@ module.exports = () => { }).then((ticketChannel) => { storage.set("userTicketStorage",ticketChannel.id,interaction.member.id) + + const hiddendata = bot.hiddenData.writeHiddenData("ticketdata",[{key:"type",value:currentTicketOptions.id},{key:"openerid",value:interaction.user.id},{key:"createdms",value:new Date().getTime()}]) var ticketEmbed = new discord.EmbedBuilder() .setAuthor({name:interaction.user.id}) .setColor(config.main_color) .setTitle(currentTicketOptions.name) .setFooter({text:"Ticket Type: "+currentTicketOptions.id}) - if (currentTicketOptions.ticketmessage.length > 0) ticketEmbed.setDescription(currentTicketOptions.ticketmessage) + if (currentTicketOptions.ticketmessage.length > 0){ + ticketEmbed.setDescription(currentTicketOptions.ticketmessage+hiddendata) + }else{ + ticketEmbed.setDescription(hiddendata) + } ticketChannel.send({ content:"<@"+interaction.member.id+"> @here", diff --git a/core/ticketReopener.js b/core/ticketReopener.js index 3ebd39f..593edd2 100755 --- a/core/ticketReopener.js +++ b/core/ticketReopener.js @@ -5,8 +5,53 @@ const config = bot.config const log = bot.errorLog.log const l = bot.language const storage = bot.storage +const pfb = discord.PermissionFlagsBits -module.exports = () => { +/** + * + * @param {discord.Guild} guild + * @param {discord.TextBasedChannel} channel + * @param {discord.User} user + * @returns + */ +const reopenTicket = (guild,channel,user) => { + log("system","re-opened a ticket",[{key:"ticket",value:channel.name},{key:"user",value:user.tag}]) + + var permissionsArray = [] + + //set everyone allowed + if (config.system['has@everyoneaccess']){ + var everyoneAllowPerms = [pfb.AddReactions,pfb.AttachFiles,pfb.EmbedLinks,pfb.SendMessages,pfb.ViewChannel] + var everyoneDenyPerms = [] + }else{ + var everyoneAllowPerms = [] + var everyoneDenyPerms = [pfb.ViewChannel] + } + permissionsArray.push({ + id:guild.roles.everyone, + type:"role", + allow:everyoneAllowPerms, + deny:everyoneDenyPerms + }) + + channel.permissionOverwrites.cache.forEach((p) => { + if (p.type == "member"){ + permissionsArray.push({ + id:p.id, + type:"member", + allow:[pfb.AddReactions,pfb.AttachFiles,pfb.EmbedLinks,pfb.SendMessages,pfb.ViewChannel], + deny:[] + }) + } + }) + + channel.permissionOverwrites.set(permissionsArray) + + require("./api/modules/events").onTicketReopen(user,channel,guild,new Date(),{name:channel.name,status:"reopened",ticketOptions:false}) +} +exports.reopenTicket = reopenTicket + +exports.runThis = () => { var closeRowNormal = new discord.ActionRowBuilder() .addComponents( new discord.ButtonBuilder() @@ -92,48 +137,7 @@ module.exports = () => { .setEmoji("🔓") ) - /** - * - * @param {discord.Guild} guild - * @param {discord.TextBasedChannel} channel - * @param {discord.User} user - * @returns - */ - const reopenTicket = (guild,channel,user) => { - log("system","re-opened a ticket",[{key:"ticket",value:channel.name},{key:"user",value:user.tag}]) - - var permissionsArray = [] - - //set everyone allowed - if (config.system['has@everyoneaccess']){ - var everyoneAllowPerms = [pfb.AddReactions,pfb.AttachFiles,pfb.EmbedLinks,pfb.SendMessages,pfb.ViewChannel] - var everyoneDenyPerms = [] - }else{ - var everyoneAllowPerms = [] - var everyoneDenyPerms = [pfb.ViewChannel] - } - permissionsArray.push({ - id:guild.roles.everyone, - type:"role", - allow:everyoneAllowPerms, - deny:everyoneDenyPerms - }) - - channel.permissionOverwrites.cache.forEach((p) => { - if (p.type == "member"){ - permissionsArray.push({ - id:p.id, - type:"member", - allow:[pfb.AddReactions,pfb.AttachFiles,pfb.EmbedLinks,pfb.SendMessages,pfb.ViewChannel], - deny:[] - }) - } - }) - - channel.permissionOverwrites.set(permissionsArray) - - require("./api/modules/events").onTicketReopen(user,channel,guild,new Date(),{name:channel.name,status:"reopened",ticketOptions:false}) - } + @@ -156,8 +160,6 @@ module.exports = () => { }) - const pfb = discord.PermissionFlagsBits - client.on("interactionCreate",(interaction) => { if (!interaction.isButton()) return if (interaction.customId != "reopenTicketTrue") return diff --git a/core/utils/errorTypes.js b/core/utils/errorTypes.js deleted file mode 100644 index 89798fc..0000000 --- a/core/utils/errorTypes.js +++ /dev/null @@ -1,3 +0,0 @@ -/** - * @typedef {String|Boolean} OTErrorType - */ \ No newline at end of file diff --git a/core/utils/getButton.js b/core/utils/getButton.js index 31ec447..5aeff34 100644 --- a/core/utils/getButton.js +++ b/core/utils/getButton.js @@ -37,7 +37,7 @@ exports.getButton = (id) => { if (!option) return false if (option.type == "ticket"){ var button = new discord.ButtonBuilder() - .setCustomId("newT"+option.id) + .setCustomId("OTnewT"+option.id) .setDisabled(false) .setStyle(getColor(option.color)) diff --git a/core/utils/hiddendata.js b/core/utils/hiddendata.js new file mode 100644 index 0000000..9920dd0 --- /dev/null +++ b/core/utils/hiddendata.js @@ -0,0 +1,52 @@ + +/**@typedef {{type:String,data:[{key:String,value:String}]}} hiddenData */ + +/** + * + * @param {String} messageContent + * @returns {hiddenData} + */ + +exports.readHiddenData = (messageContent) => { + //ticketdata//type:123|userid:456) + const rawhidden = messageContent.split("[ ](OTDATA|")[1] + const rawhidden2 = rawhidden.split("//") + + const datatype = rawhidden2[0] + var rawhiddendata = rawhidden2[1] + var rawhiddendataArray = rawhiddendata.split("") + rawhiddendataArray.pop() + + rawhiddendata = rawhiddendataArray.join("") + + const splittedData = rawhiddendata.split("|") + + const resultData = [] + splittedData.forEach((data) => { + // type:123 + const dataresult = data.split(":") + + resultData.push({key:dataresult[0],value:dataresult[1]}) + }) + + return {type:datatype,data:resultData} +} + +/** + * + * @param {String} type + * @param {[{key:String,value:String}]} data + * @returns {String} + */ +exports.writeHiddenData = (type,data) => { + const dataValues = [] + data.forEach((d) => { + dataValues.push(d.key+":"+d.value) + }) + + const datastring = dataValues.join("|") + + const result = "[ ](OTDATA|"+type+"//"+datastring+")" + + return result +} \ No newline at end of file diff --git a/index.js b/index.js index c9ce310..9f5bde3 100644 --- a/index.js +++ b/index.js @@ -26,7 +26,7 @@ const client = new discord.Client({ }) exports.client = client -client.setMaxListeners(30) +client.setMaxListeners(50) if (process.argv[2]){ if (process.argv[2].endsWith("d")){ @@ -48,9 +48,22 @@ if (isDev){ } }else{var config = require('./config.json')} exports.config = config +exports.storage = require('./core/dynamicdatabase/storage') + exports.errorLog = require("./core/errorLogSystem") const log = this.errorLog.log +exports.hiddenData = require("./core/utils/hiddendata") + +exports.embeds = { + commands:require("./core/interactionHandlers/embeds/commands") +} +exports.buttons = { + close:require("./core/interactionHandlers/buttons/close"), + firstmsg:require("./core/interactionHandlers/buttons/firstmsg"), + verifybars:require("./core/interactionHandlers/buttons/verifyBars") +} + client.on('ready',async () => { var statusSet = false const setStatus = (type,text) => { @@ -129,25 +142,26 @@ if (!isDev){ if (process.argv[2] && process.argv[2].startsWith("slash")){ //do nothing }else{ - var storage = require('./core/dynamicdatabase/storage') - exports.storage = storage //commands - require('./commands/ticket')() - require("./commands/help")() - require("./commands/close")() - require("./commands/delete")() - require("./commands/rename")() - require("./commands/add")() - require("./commands/remove")() - require("./commands/reopen")() + require('./commands/ticket')(this) + require("./commands/help")(this) + require("./commands/close")(this) + require("./commands/delete")(this) + require("./commands/rename")(this) + require("./commands/add")(this) + require("./commands/remove")(this) + require("./commands/reopen")(this) //core - require('./core/ticketOpener')() - require("./core/ticketCloser").runThis() - require("./core/closebuttons")() - require("./core/reactionRoles")() - require("./core/ticketReopener")() + require('./core/ticketOpener')(this) + require("./core/ticketCloser").runThis(this) + require("./core/closebuttons")(this) + require("./core/reactionRoles")(this) + require("./core/ticketReopener").runThis(this) + + //InteractionHandlers + require("./core/interactionHandlers/handlers/handlers")() } diff --git a/language/english.json b/language/english.json index 530d5bf..47b495b 100644 --- a/language/english.json +++ b/language/english.json @@ -3,7 +3,8 @@ "missingArgsTitle":"Invalid Arguments!", "missingArgsDescription":"Missing Argument", "noPermsTitle":"No Permissions!", - "noPermsDescription":"You don't have the correct roles to run this command!\nYou need the `ADMINISTRATOR` permission or be in the list of allowed roles!", + "noPermsDescription":"You need the `ADMINISTRATOR` permission or be in the list of allowed roles!", + "noPermsDelete":"Only admins can delete a ticket!", "chooseFromListTitle":"Invalid ID", "chooseFromListDescription":"Choose one of the id's below:", "boterror":"Bot Error!", @@ -18,26 +19,18 @@ "somethingWentWrongTranscript":"Something went wrong while making the transcript!**\nPlease try again another time!" }, "commands":{ - "userAddedTitle":"User Added!", - "userAddedDescription":"{0} is added to this ticket!", - "userRemovedTitle":"User Removed!", - "userRemovedDescription":"{0} is removed from this ticket!", - - "renameTitle":"The name is changed!", - "renameWarning":"Warning: you can only change the channel name 2 times per minute!\n(this is due discord rate limits)", - - "closeTitle":"Close this ticket!", - "closeDescription":"You can close this ticket by clicking on the button below!", - "deleteTitle":"Delete this ticket!", - "deleteDescription":"You can delete this ticket by clicking on the button below!", - "reopenTitle":"Re-Open this ticket!", - "reopenDescription":"You can re-open this ticket by clicking on the button below!", + "userAddedTitle":"Added {0} to this ticket!", + "userRemovedTitle":"Removed {0} from this ticket!", + "renameTitle":"Changed the name to {0}!", + "closeTitle":"Closed this ticket!", + "deleteTitle":"Deleting this ticket...", + "reopenTitle":"Re-Opened this ticket!", "ticketWarning":"The embed is in the message below!", "maxTicketWarning":"**Warning:** _You can only create {0} ticket(s) at a time!_" }, "helpMenu":{ - "title":"Help Menu:", + "title":"Available Commands:", "header1":"**Go to {0} to create a ticket!**\n\n", "header2":"**Run the command `/new` or `/ticket` to create a ticket!**\n\n", @@ -53,7 +46,7 @@ "close":"Close Ticket", "delete":"Delete Ticket", "reopen":"Re-Open Ticket", - "sendTranscript":"Send Transcript File" + "sendTranscript":"Transcript" }, "messages":{ "reopenTitle":"Re-Opened this ticket!", @@ -71,7 +64,6 @@ "reopenTicketDmTitle":"Ticket Re-opened!", "reopenTicketDmDescription":"Your ticket is re-opened!", "newTranscriptTitle":"A new transcript is here!", - "newTranscriptDescription":"You can find the transcript in the text file above!", "hereIsTheTranscript":"Here is the transcript:", "chooseCategory":"choose a category:", diff --git a/package.json b/package.json index 407b2d3..817eebe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-ticket", - "version": "2.4.0", + "version": "2.5.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": {