diff --git a/README.md b/README.md index 9a9fe41..a5be7c1 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.3.3%20stable-brightgreen.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/releases/tag/v2.3.3) [![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.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) This is an open-source discord ticket bot, you can configure it and it comes with cool features like transcripts & custom options! @@ -18,51 +18,57 @@ This is an open-source discord ticket bot, you can configure it and it comes wit ### Thanks to these people: - DJ-Lite: for doing the administration - Sanke: for translation & new ideas +- Everyone that reported a bug +#### And our translators! - ExothDE: for translation - 1x1: for translation - R0JO: for translation -- Everyone that reported a bug +- t0miiis for translation ## features -- discord buttons +- discord interaction buttons - slash & text commands - close, delete & re-open tickets -- translation (we are searching for translators!) +- translation in 8 different languages - dynamic database system -- advanced transcripts +- transcripts - add/remove users from a ticket -- large embed customisation -- create custom ticket names, icons & colors -- create url's & reaction roles! -- uses discord.js v13 -- configure your own ticket options -- remove credits if you want (don't do it please 😉) -- unlimited tickets at the same time +- custom colors & name for embeds +- customise your ticket +- create url buttons for websites +- create reaction roles +- build with discord.js v14 +- configure everything per ticket +- remove credits if you want :( +- unlimited tickets spread over multiple messages + +*comming soon:* +- dashboard +- view transcripts in dashboard +- share transcripts +- close with reason +- more translation ## installation **You need `node.js 16` to run this project!** -**At this moment you still need discord.js v13!** -This will change soon! - -You can clone or download this project. - ### packages - chalk => version `latest` - discord.js => version `latest` - express => version `latest` - node-localstorage => version `latest` +- axios => version `latest` You can install all of them by running `npm install` ## running you can run `node index.js` but i would recommend you to use `npm start` -if there are any errors, you can open an **issue on github** or **contact me in the discord server**. +if there are any errors, you can open an **issue on github** or **contact me in our discord server**. ### config Our config documentation is moved to another file: -[click here to view](https://www.github.com/DJj123dj/open-ticket/wiki/config-v2.3.3) +[click here to view](https://www.github.com/DJj123dj/open-ticket/wiki/config-v2.4.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 @@ -74,8 +80,8 @@ You can also configure your own permissions ## information -_v2.3.3 stable_ +_v2.4.0 stable_ changelog: [click here](https://www.github.com/DJj123dj/open-ticket/wiki/Changelog) -© 2022 - DJdj Development | [website](https://www.dj-dj.be) | [discord](https://discord.com/invite/26vT9wt3n3) \ No newline at end of file +© 2022 - DJdj Development | [website](https://www.dj-dj.be) | [discord](https://discord.dj-dj.be) | [terms of service](https://www.dj-dj.be/terms) \ No newline at end of file diff --git a/commands/add.js b/commands/add.js index 8bdccd5..be5b848 100644 --- a/commands/add.js +++ b/commands/add.js @@ -4,6 +4,9 @@ const client = bot.client const config = bot.config const log = bot.errorLog.log const l = bot.language +const permsChecker = require("../core/utils/permisssionChecker") + +const APIEvents = require("../core/api/modules/events") module.exports = () => { client.on("messageCreate",msg => { @@ -11,12 +14,10 @@ module.exports = () => { var user = msg.mentions.users.first() if (!user) return msg.channel.send({embeds:[bot.errorLog.invalidArgsMessage(l.errors.missingArgsDescription+" ``:\n`"+config.prefix+"add `")]}) - if (!msg.member.permissions.has("ManageChannels") && !msg.member.permissions.has("Administrator") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ - try { - return msg.member.send({embeds:[bot.errorLog.noPermsMessage]}) - }catch{ - return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) - } + if (!msg.guild) return + if (!permsChecker.command(msg.author.id,msg.guild.id)){ + permsChecker.sendUserNoPerms(msg.author) + return } msg.channel.messages.fetchPinned().then(msglist => { @@ -30,6 +31,12 @@ module.exports = () => { 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) + 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()) }) }) @@ -39,11 +46,13 @@ module.exports = () => { if (interaction.commandName != "add") return const user = interaction.options.getUser("user") - const permsmember = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (config.main_adminroles.some((item)=>{return permsmember.roles.cache.has(item)}) == false && !permsmember.permissions.has("Administrator") && !permsmember.permissions.has("ManageGuild")){ - interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) - return - } + 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() @@ -56,6 +65,12 @@ module.exports = () => { 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) + 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 be19429..3c622f1 100644 --- a/commands/close.js +++ b/commands/close.js @@ -4,6 +4,9 @@ const client = bot.client const config = bot.config const log = bot.errorLog.log const l = bot.language +const permsChecker = require("../core/utils/permisssionChecker") + +const APIEvents = require("../core/api/modules/events") module.exports = () => { client.on("messageCreate",msg => { @@ -27,6 +30,7 @@ module.exports = () => { msg.channel.send({embeds:[bot.errorLog.success(l.commands.closeTitle,l.commands.closeDescription)],components:[closebutton]}) 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()) }) @@ -37,6 +41,8 @@ module.exports = () => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "close") return + interaction.deferReply() + interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() @@ -54,6 +60,7 @@ module.exports = () => { interaction.reply({embeds:[bot.errorLog.success(l.commands.closeTitle,l.commands.closeDescription)],components:[closebutton]}) 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 199f678..e3f1190 100644 --- a/commands/delete.js +++ b/commands/delete.js @@ -4,17 +4,18 @@ const client = bot.client const config = bot.config const log = bot.errorLog.log const l = bot.language +const permsChecker = require("../core/utils/permisssionChecker") + +const APIEvents = require("../core/api/modules/events") module.exports = () => { client.on("messageCreate",msg => { if (!msg.content.startsWith(config.prefix+"delete")) return - if (!msg.member.permissions.has("ManageChannels") && !msg.member.permissions.has("Administrator") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ - try { - return msg.member.send({embeds:[bot.errorLog.noPermsMessage]}) - }catch{ - return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) - } + if (!msg.guild) return + if (!permsChecker.command(msg.author.id,msg.guild.id)){ + permsChecker.sendUserNoPerms(msg.author) + return } msg.channel.messages.fetchPinned().then(msglist => { @@ -34,7 +35,7 @@ module.exports = () => { msg.channel.send({embeds:[bot.errorLog.success(l.commands.deleteTitle,l.commands.deleteDescription)],components:[closebutton]}) 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()) }) @@ -44,11 +45,13 @@ module.exports = () => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "delete") return - const permsmember = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (config.main_adminroles.some((item)=>{return permsmember.roles.cache.has(item)}) == false && !permsmember.permissions.has("Administrator") && !permsmember.permissions.has("ManageGuild")){ - interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) - return - } + interaction.deferReply() + + if (!interaction.guild) return + if (!permsChecker.command(interaction.user.id,interaction.guild.id)){ + permsChecker.sendUserNoPerms(interaction.user) + return + } interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() @@ -67,6 +70,7 @@ module.exports = () => { interaction.reply({embeds:[bot.errorLog.success(l.commands.deleteTitle,l.commands.deleteDescription)],components:[closebutton]}) log("command","someone used the 'close' 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 5c925b0..25df27e 100644 --- a/commands/help.js +++ b/commands/help.js @@ -5,6 +5,8 @@ const config = bot.config const log = bot.errorLog.log const l = bot.language +const APIEvents = require("../core/api/modules/events") + module.exports = () => { const helpEmbed = new discord.EmbedBuilder() .setColor(config.main_color) @@ -24,6 +26,7 @@ module.exports = () => { if (!args[1]){ 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 } @@ -31,6 +34,7 @@ module.exports = () => { 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()) } }) @@ -40,5 +44,6 @@ module.exports = () => { interaction.reply({embeds:[helpEmbed]}) log("command","someone used the 'help' command",[{key:"user",value:interaction.user.tag}]) + APIEvents.onCommand("help",true,interaction.user,interaction.channel,interaction.guild,new Date()) }) } \ No newline at end of file diff --git a/commands/remove.js b/commands/remove.js index ce38a4f..29730b3 100644 --- a/commands/remove.js +++ b/commands/remove.js @@ -4,6 +4,9 @@ const client = bot.client const config = bot.config const log = bot.errorLog.log const l = bot.language +const permsChecker = require("../core/utils/permisssionChecker") + +const APIEvents = require("../core/api/modules/events") module.exports = () => { client.on("messageCreate",msg => { @@ -11,14 +14,14 @@ module.exports = () => { var user = msg.mentions.users.first() if (!user) return msg.channel.send({embeds:[bot.errorLog.invalidArgsMessage(l.errors.missingArgsDescription+" ``:\n`"+config.prefix+"remove `")]}) - if (!msg.member.permissions.has("ManageChannels") && !msg.member.permissions.has("Administrator") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ - try { - return msg.member.send({embeds:[bot.errorLog.noPermsMessage]}) - }catch{ - return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) - } + if (!msg.guild) return + if (!permsChecker.command(msg.author.id,msg.guild.id)){ + permsChecker.sendUserNoPerms(msg.author) + return } + interaction.deferReply() + msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() @@ -31,6 +34,11 @@ module.exports = () => { 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) + 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()) }) }) @@ -40,11 +48,11 @@ module.exports = () => { if (interaction.commandName != "remove") return const user = interaction.options.getUser("user") - const permsmember = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (config.main_adminroles.some((item)=>{return permsmember.roles.cache.has(item)}) == false && !permsmember.permissions.has("Administrator") && !permsmember.permissions.has("ManageGuild")){ - interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) - return - } + if (!interaction.guild) return + if (!permsChecker.command(interaction.user.id,interaction.guild.id)){ + permsChecker.sendUserNoPerms(interaction.user) + return + } @@ -60,6 +68,11 @@ module.exports = () => { 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) + 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()) }) diff --git a/commands/rename.js b/commands/rename.js index 370d0e4..e9ef4ef 100644 --- a/commands/rename.js +++ b/commands/rename.js @@ -4,6 +4,9 @@ const client = bot.client const config = bot.config const log = bot.errorLog.log const l = bot.language +const permsChecker = require("../core/utils/permisssionChecker") + +const APIEvents = require("../core/api/modules/events") module.exports = () => { client.on("messageCreate",msg => { @@ -14,12 +17,10 @@ module.exports = () => { if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) - if (!msg.member.permissions.has("ManageChannels") && !msg.member.permissions.has("Administrator") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ - try { - return msg.member.send({embeds:[bot.errorLog.noPermsMessage]}) - }catch{ - return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) - } + if (!msg.guild) return + if (!permsChecker.command(msg.author.id,msg.guild.id)){ + permsChecker.sendUserNoPerms(msg.author) + return } var newname = msg.content.split(config.prefix+"rename")[1].substring(1) @@ -42,7 +43,7 @@ module.exports = () => { 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}]) - + APIEvents.onCommand("rename",permsChecker.command(msg.author.id,msg.guild.id),msg.author,msg.channel,msg.guild,new Date()) }) @@ -52,14 +53,16 @@ module.exports = () => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "rename") 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 permsmember = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (config.main_adminroles.some((item)=>{return permsmember.roles.cache.has(item)}) == false && !permsmember.permissions.has("Administrator") && !permsmember.permissions.has("ManageGuild")){ - interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) + if (!interaction.guild) return + if (!permsChecker.command(interaction.user.id,interaction.guild.id)){ + permsChecker.sendUserNoPerms(interaction.user) return } @@ -80,7 +83,8 @@ module.exports = () => { 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}]) - + + APIEvents.onCommand("rename",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/reopen.js b/commands/reopen.js index b1af86a..20e6e6f 100644 --- a/commands/reopen.js +++ b/commands/reopen.js @@ -4,6 +4,9 @@ const client = bot.client const config = bot.config const log = bot.errorLog.log const l = bot.language +const permsChecker = require("../core/utils/permisssionChecker") + +const APIEvents = require("../core/api/modules/events") module.exports = () => { var reopenCommandBar = new discord.ActionRowBuilder() @@ -27,23 +30,31 @@ module.exports = () => { 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()) }) }) - client.on("interactionCreate",(interaction) => { + client.on("interactionCreate",async (interaction) => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "reopen") return - interaction.channel.messages.fetchPinned().then(msglist => { + await interaction.deferReply() + + interaction.channel.messages.fetchPinned().then(async msglist => { var firstmsg = msglist.last() if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) - interaction.reply({embeds:[bot.errorLog.success(l.commands.reopenTitle,l.commands.reopenDescription)],components:[reopenCommandBar]}) + 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]}) + } 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/commands/ticket.js b/commands/ticket.js index 1586d28..d64d7c4 100644 --- a/commands/ticket.js +++ b/commands/ticket.js @@ -4,6 +4,9 @@ const client = bot.client const config = bot.config const log = bot.errorLog.log const l = bot.language +const permsChecker = require("../core/utils/permisssionChecker") + +const APIEvents = require("../core/api/modules/events") module.exports = () => { /**@type {String[]} */ @@ -16,12 +19,10 @@ module.exports = () => { client.on("messageCreate", msg => { if (msg.content.startsWith(config.prefix+"msg"||config.prefix+"message")){ - if (!msg.member.permissions.has("ManageChannels") && !msg.member.permissions.has("Administrator") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ - try { - return msg.member.send({embeds:[bot.errorLog.noPermsMessage]}) - }catch{ - return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) - } + if (!msg.guild) return + if (!permsChecker.command(msg.author.id,msg.guild.id)){ + permsChecker.sendUserNoPerms(msg.author) + return } const id = msg.content.split(config.prefix+"msg")[1].substring(1) ? msg.content.split(config.prefix+"msg")[1].substring(1) : false @@ -34,7 +35,8 @@ module.exports = () => { msg.channel.send({embeds:[embed],components:componentRows}) - log("command","someone used the 'msg' command",[{key:"user",value:msg.author.tag},{key:"id",value:id}]) + log("command","someone used the 'message' command",[{key:"user",value:msg.author.tag},{key:"id",value:id}]) + APIEvents.onCommand("message",permsChecker.command(msg.author.id,msg.guild.id),msg.author,msg.channel,msg.guild,new Date()) } }) @@ -42,11 +44,11 @@ module.exports = () => { if (!interaction.isChatInputCommand()) return if (interaction.commandName != "message") return - const permsmember = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (config.main_adminroles.some((item)=>{return permsmember.roles.cache.has(item)}) == false && !permsmember.permissions.has("Administrator") && !permsmember.permissions.has("ManageGuild")){ - interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) - return - } + if (!interaction.guild) return + if (!permsChecker.command(interaction.user.id,interaction.guild.id)){ + permsChecker.sendUserNoPerms(interaction.user) + return + } const id = interaction.options.getString("id") @@ -57,7 +59,9 @@ module.exports = () => { interaction.reply({content:l.commands.ticketWarning}) interaction.channel.send({embeds:[embed],components:componentRows}) - log("command","someone used the 'msg' command",[{key:"user",value:interaction.user.tag},{key:"id",value:id}]) + log("command","someone used the 'message' command",[{key:"user",value:interaction.user.tag},{key:"id",value:id}]) + + APIEvents.onCommand("message",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/config.json b/config.json index e4465fd..8a8ccbf 100644 --- a/config.json +++ b/config.json @@ -1,5 +1,4 @@ { - "bot_name":"Wumpus", "main_color":"#ffffff", "server_id":"server id (for slash cmds)", "auth_token":"auth token", @@ -78,11 +77,16 @@ "id":"1", "name":"Choose Your Ticket", "description":"You can click one of the buttons below!", + "enableFooter":false, - "footer":"Open Ticket v2.3.3 - I'm a footer!", + "footer":"Open Ticket v2.4.0 - I'm a footer!", + "enableThumbnail":false, "thumbnail":"https://www.example.com/catmemes/cat.png", + + "enableCustomColor":false, "color":"#ffffff", + "options":["general","apply"], "enableTicketExplaination":true, "enableMaxTicketsWarning":true diff --git a/core/api/api docs.md b/core/api/api docs.md deleted file mode 100644 index c8b0832..0000000 --- a/core/api/api docs.md +++ /dev/null @@ -1,56 +0,0 @@ -# OT-API Documentation -Extend open ticket with your own features! - -The api is made for EXTENDING open ticket, not replacing! So with this api you are not able to replace existing features! You can only add your own features! - -### DISCLAIMER: -Only edit or extend the code when you know what you are doing! - -If open ticket crashes while you change the code, then we can't help you! - -**DO IT ON YOUR OWN RISK!** - -## Events: -Everything in the `events.js` file! - -### onTicketOpen(...) -This function is executed when a new ticket is created. It happens after everything else is done, so the channel is already created! - -Parameters: -- user: `discord.User` -- channel: `discord.TextChannel` -- guild: `discord.Guild` -- date: `Date` -- ticketdata: `OT TicketData` or `false` (more info further down this document) - -### onTicketClose(...) -This function is executed when a ticket gets closed, it can happen multiple times with one ticket (because of reopen). - -Parameters: -- user: `discord.User` -- channel: `discord.TextChannel` -- guild: `discord.Guild` -- date: `Date` -- ticketdata: `OT TicketData` or `false` (more info further down this document) - -### onTicketDelete(...) -This function is executed when a ticket gets deleted, it can happen only 1 time. - -Parameters: -- user: `discord.User` -- channel: `discord.TextChannel` -- guild: `discord.Guild` -- date: `Date` -- ticketdata: `OT TicketData` or `false` (more info further down this document) - -### onTicketReopen(...) -... - -### onTranscriptCreation(...) -... - -### onCommand(...) -... - -### onReactionRole(...) -... \ No newline at end of file diff --git a/core/api/api.js b/core/api/api.js new file mode 100644 index 0000000..03c633f --- /dev/null +++ b/core/api/api.js @@ -0,0 +1,18 @@ +//base +const bot = require("../../index") + +exports.client = bot.client +exports.config = bot.config +exports.utils = { + log:bot.errorLog.log(), + storage:bot.storage +} + +//events +const events = require("./modules/events").events +exports.events = events + +//actions +const actions = require("./modules/actions").actions +//comming soon +//exports.actions = actions \ No newline at end of file diff --git a/core/api/api.json b/core/api/api.json index ea2feef..03dd942 100644 --- a/core/api/api.json +++ b/core/api/api.json @@ -1,3 +1,46 @@ { - "version":"1.0.0" + "version":"1.0.0", + + + "disclaimer":"DISABLE doesn't work yet! Below this message!", + "disable":{ + "messages":{ + "ticketCreated":false, + "ticketClosed":false, + "ticketDeleted":false, + "ticketReopened":false + }, + "transcripts":{ + "server":false, + "dm":false + }, + "commands":{ + "text":{ + "help":false, + "msg":false, + "close":false, + "delete":false, + "reopen":false, + "new":false, + "add":false, + "remove":false, + "rename":false + }, + "slash":{ + "help":false, + "msg":false, + "close":false, + "delete":false, + "reopen":false, + "new":false, + "add":false, + "remove":false, + "rename":false + } + }, + "checkerjs":{ + "token":false, + "all":false + } + } } \ No newline at end of file diff --git a/core/api/modules/actions.js b/core/api/modules/actions.js new file mode 100644 index 0000000..55fc01f --- /dev/null +++ b/core/api/modules/actions.js @@ -0,0 +1,7 @@ +//ACTIONS: + + +//EXPORT ACTIONS: +exports.actions = { + +} \ No newline at end of file diff --git a/core/api/modules/base.js b/core/api/modules/base.js index 1da67c2..1f96c22 100644 --- a/core/api/modules/base.js +++ b/core/api/modules/base.js @@ -14,6 +14,8 @@ const storage = bot.storage //used when creating plugins! exports.enableApiLogs = false + +//DOESN'T WORK YET //this is used when embedding open ticket into another bot exports.embeddedMode = false exports.clientLocation = require("../../../index").client diff --git a/core/api/modules/custom.js b/core/api/modules/custom.js deleted file mode 100644 index 1ef099d..0000000 --- a/core/api/modules/custom.js +++ /dev/null @@ -1,9 +0,0 @@ -const discord = require("discord.js") -const client = require("../../../index").client - -module.exports = () => { - //this code will run when the bot starts! - - - -} \ No newline at end of file diff --git a/core/api/modules/events.js b/core/api/modules/events.js index 14601f2..7014799 100644 --- a/core/api/modules/events.js +++ b/core/api/modules/events.js @@ -6,6 +6,22 @@ const log = bot.errorLog.log const l = bot.language const storage = bot.storage + +//EVENT API: +const ticketOpenListeners = [] +const ticketCloseListeners = [] +const ticketDeleteListeners = [] +const ticketReopenListeners = [] + +const ticketAddListeners = [] +const ticketRemoveListeners = [] + + +const transcriptCreationListeners = [] +const commandListeners = [] +const reactionRoleListeners = [] +const errorListeners = [] + /** * * @param {discord.User} user @@ -18,7 +34,11 @@ exports.onTicketOpen = (user,channel,guild,date,ticketdata) => { //system bot.errorLog.log("api","new ticket created",[{key:"userid",value:user.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)}]) - //custom code + ticketOpenListeners.forEach((func) => { + try { + func(user,channel,guild,date,ticketdata) + }catch{} + }) } @@ -34,7 +54,11 @@ exports.onTicketClose = (user,channel,guild,date,ticketdata) => { //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)}]) - //custom code + ticketCloseListeners.forEach((func) => { + try { + func(user,channel,guild,date,ticketdata) + }catch{} + }) } @@ -50,6 +74,276 @@ exports.onTicketDelete = (user,channel,guild,date,ticketdata) => { //system bot.errorLog.log("api","ticket deleted",[{key:"userid",value:user.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)}]) - //custom code + ticketDeleteListeners.forEach((func) => { + try { + func(user,channel,guild,date,ticketdata) + }catch{} + }) +} + +/** + * + * @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 + */ +exports.onTicketReopen = (user,channel,guild,date,ticketdata) => { + //system + bot.errorLog.log("api","ticket reopened",[{key:"userid",value:user.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)}]) + + ticketReopenListeners.forEach((func) => { + try { + func(user,channel,guild,date,ticketdata) + }catch{} + }) + +} + +/** + * + * @param {discord.User} user + * @param {discord.User} editeduser + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:Object|false}} ticketdata + */ +exports.onTicketAdd = (user,editeduser,channel,guild,date,ticketdata) => { + //system + bot.errorLog.log("api","user added to ticket",[{key:"userid",value:user.id},{key:"editeduser",value:editeduser.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)}]) + + ticketAddListeners.forEach((func) => { + try { + func(user,editeduser,channel,guild,date,ticketdata) + }catch{} + }) + +} + +/** + * + * @param {discord.User} user + * @param {discord.User} editeduser + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:Object|false}} ticketdata + */ +exports.onTicketRemove = (user,editeduser,channel,guild,date,ticketdata) => { + //system + bot.errorLog.log("api","user removed from ticket",[{key:"userid",value:user.id},{key:"editeduser",value:editeduser.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)}]) + + ticketRemoveListeners.forEach((func) => { + try { + func(user,editeduser,channel,guild,date,ticketdata) + }catch{} + }) + +} + +/** + * + * @param {discord.Message[]} messages + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + */ +exports.onTranscriptCreation = (messages,channel,guild,date) => { + //system + bot.errorLog.log("api","transcript created",[{key:"messages",value:JSON.stringify(messages)},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id}]) + + transcriptCreationListeners.forEach((func) => { + try { + func(messages,channel,guild,date) + }catch{} + }) + +} + +/**@typedef {"help"|"message"|"close"|"delete"|"reopen"|"rename"|"add"|"remove"} OTCommandType */ + +/** + * + * @param {OTCommandType} type + * @param {Boolean} hasPerms + * @param {discord.User} user + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + */ +exports.onCommand = (type,hasPerms,user,channel,guild,date) => { + //system + bot.errorLog.log("api","someone used a command",[{key:"type",value:type},{key:"hasPerms",value:hasPerms},{key:"userid",value:user},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id}]) + + commandListeners.forEach((func) => { + try { + func(type,hasPerms,user,channel,guild,date) + }catch{} + }) + +} + +/**@typedef {"add"|"remove"|"add&remove"} OTReactionRoleType */ +/**@typedef {"add"|"remove"} OTReactionRoleMode */ + +/** + * @param {OTReactionRoleMode} mode + * @param {OTReactionRoleType} type + * @param {discord.Role} role + * @param {discord.User} user + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + */ + exports.onReactionRole = (mode,type,role,user,channel,guild,date) => { + //system + bot.errorLog.log("api","someone used a reaction role",[{key:"mode",value:mode},{key:"type",value:type},{key:"roleid",value:role.id},{key:"userid",value:user},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id}]) + + reactionRoleListeners.forEach((func) => { + try { + func(mode,type,role,user,channel,guild,date) + }catch{} + }) + +} + +/** + * @param {String} err + * @param {Date} date + */ + exports.onError = (err,date) => { + //system + bot.errorLog.log("api","there is an error",[{key:"error",value:err}]) + + errorListeners.forEach((func) => { + try { + func(err,date) + }catch{} + }) + +} + + +//EVENT CALLBACKS: + +/** + * @callback TicketActionEvent + * @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 + */ + +/** + * @callback TranscriptCreationEvent + * @param {discord.Message[]} messages + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + */ + +/** + * @callback TicketUserChangeEvent + * @param {discord.User} user + * @param {discord.User} editeduser + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:Object|false}} ticketdata + */ + +/** + * @callback CommandEvent + * @param {OTCommandType} type + * @param {Boolean} hasPerms + * @param {discord.User} user + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + */ + +/** + * @callback ReactionRoleEvent + * @param {OTReactionRoleMode} mode + * @param {OTReactionRoleType} type + * @param {discord.Role} role + * @param {discord.User} user + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + */ + +/** + * @callback ErrorEvent + * @param {String} error + * @param {Date} date + */ + +//EVENT EXPORT: + +/**@param {TicketActionEvent} callback */ +const onTicketOpen = (callback) => { + ticketOpenListeners.push(callback) +} + +/**@param {TicketActionEvent} callback */ +const onTicketClose = (callback) => { + ticketCloseListeners.push(callback) +} + +/**@param {TicketActionEvent} callback */ +const onTicketDelete = (callback) => { + ticketDeleteListeners.push(callback) +} + +/**@param {TicketActionEvent} callback */ +const onTicketReopen = (callback) => { + ticketReopenListeners.push(callback) +} + +/**@param {TicketUserChangeEvent} callback */ +const onTicketAdd = (callback) => { + ticketAddListeners.push(callback) +} + +/**@param {TicketUserChangeEvent} callback */ +const onTicketRemove = (callback) => { + ticketRemoveListeners.push(callback) +} + +/**@param {TranscriptCreationEvent} callback */ +const onTranscriptCreation = (callback) => { + transcriptCreationListeners.push(callback) +} + +/**@param {CommandEvent} callback */ +const onCommand = (callback) => { + commandListeners.push(callback) +} + +/**@param {ReactionRoleEvent} callback */ +const onReactionRole = (callback) => { + commandListeners.push(callback) +} + +/**@param {ErrorEvent} callback */ +const onError = (callback) => { + errorListeners.push(callback) +} + +exports.events = { + onTicketOpen, + onTicketClose, + onTicketDelete, + onTicketReopen, + onTicketAdd, + onTicketRemove, + onTranscriptCreation, + onCommand, + onReactionRole, + onError } \ No newline at end of file diff --git a/core/api/pluginlauncher.js b/core/api/pluginlauncher.js new file mode 100644 index 0000000..3c5a34d --- /dev/null +++ b/core/api/pluginlauncher.js @@ -0,0 +1,26 @@ +const fs = require("fs") +const bot = require("../../index") +const log = bot.errorLog.log + +module.exports = () => { + const files = fs.readdirSync("./plugins") + + var totalcount = 0 + var successcount = 0 + var failcount = 0 + files.forEach((file) => { + if (file.endsWith(".plugin.js")){ + try { + require("../../plugins/"+file)() + + successcount++ + totalcount++ + }catch{ + failcount++ + totalcount++ + } + } + }) + + log("info","loaded plugins",[{key:"success",value:successcount},{key:"error",value:failcount},{key:"total",value:totalcount}]) +} \ No newline at end of file diff --git a/core/checker.js b/core/checker.js index 4a31ebd..0a2e6b2 100644 --- a/core/checker.js +++ b/core/checker.js @@ -25,7 +25,7 @@ exports.checker = async () => { if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){ createError("'"+path+"' | this channel id is invalid") } - }else if (mode == "roleid"){ + }else if (mode == "roleid"){ if (value.length < 16 || value.length > 20 || !/^\d+$/.test(value)){ createError("'"+path+"' | this role id is invalid") } @@ -41,7 +41,7 @@ exports.checker = async () => { } /**@param {String} value */ const checkToken = (value) => { - if (value.includes(" ") || value.length < 40 || value.length > 70){ + if (value.includes(" ") || value.length < 40 || value.length > 90){ createError("'auth_token' | your token is invalid") } } @@ -245,14 +245,13 @@ exports.checker = async () => { //--------------------------| //--------------------------| - var configArray = ["bot_name","main_color","server_id","auth_token","main_adminroles","prefix","languagefile","credits","status","system","options","messages"] + var configArray = ["main_color","server_id","auth_token","main_adminroles","prefix","languagefile","credits","status","system","options","messages"] configArray.forEach((item) => { if (config[item] == undefined){ throw new Error("\n\nMAIN ERROR: the item '"+item+"' doesn't exist in config.json") } }) - - checkType(config.bot_name,"string","bot_name") + checkHexColor(config.main_color,"main_color") checkDiscord("serverid",config.server_id,"server_id") checkToken(config.auth_token) @@ -310,6 +309,28 @@ exports.checker = async () => { checkOption(option,"options/"+index) }) + + //discord check + /** + const discord = require("discord.js") + const {GatewayIntentBits,Partials} = discord + const client = new discord.Client({ + intents:[ + GatewayIntentBits.DirectMessages, + GatewayIntentBits.GuildInvites, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.Guilds, + GatewayIntentBits.MessageContent + ], + partials:[Partials.Channel,Partials.Message] + }) + await client.guilds.fetch() + if (!client.guilds.cache.find(g => g.id == config.server_id)){ + createError("'server_id' | i'm not in a server with this id!") + } + */ + //the end diff --git a/core/closebuttons.js b/core/closebuttons.js index 255a4f8..03e1d7c 100644 --- a/core/closebuttons.js +++ b/core/closebuttons.js @@ -167,7 +167,7 @@ module.exports = () => { } }) - await require("./ticketCloser").closeTicket(interaction,prefix,"close") + await require("./ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"close") closeTicketButtonChecker = false }) @@ -218,7 +218,7 @@ module.exports = () => { } }) - await require("./ticketCloser").closeTicket(interaction,prefix,"close") + await require("./ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"close") closeTicket1ButtonChecker = false }) @@ -270,7 +270,7 @@ module.exports = () => { } }) - await require("./ticketCloser").closeTicket(interaction,prefix,"delete") + await require("./ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"delete") deleteTicketButtonChecker = false }) @@ -325,7 +325,7 @@ module.exports = () => { } }) - await require("./ticketCloser").closeTicket(interaction,prefix,"deletenotranscript") + await require("./ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"deletenotranscript") deleteTicket1ButtonChecker = false }) } \ No newline at end of file diff --git a/core/errorLogSystem.js b/core/errorLogSystem.js index 7a11162..169f8b7 100644 --- a/core/errorLogSystem.js +++ b/core/errorLogSystem.js @@ -92,8 +92,8 @@ const normalLog = (debugString) => { * @param {String} message * @param {[{key:String,value:String}]} params */ -exports.log = async (ptype,message,params) => { - var type = ptype +exports.log = async (type,message,params) => { + var ptype = type const chalk = await loadChalk() var paramstring = "" if (params){ @@ -105,20 +105,20 @@ exports.log = async (ptype,message,params) => { } const parameters = params ? "("+paramstring+")" : " " - if (type == "command"){ + if (ptype == "command"){ console.log(chalk.green("[command] ")+message+" "+chalk.yellow(parameters)) - }else if (type == "info"){ + }else if (ptype == "info"){ console.log(chalk.blue("[info] ")+message+" "+chalk.yellow(parameters)) - }else if (type == "system"){ + }else if (ptype == "system"){ console.log(chalk.green("[system] ")+message+" "+chalk.yellow(parameters)) - }else if (type == "api"){ + }else if (ptype == "api"){ if (require("./api/modules/base").enableApiLogs == true){ console.log(chalk.red("[api v"+require("./api/api.json").version+"] ")+message+" "+chalk.yellow(parameters)) } - type = "api v"+require("./api/api.json").version + ptype = "api v"+require("./api/api.json").version } const cd = new Date() const months = ["January","February","March","April","May","June","July","August","September","October","November","December"] - normalLog("["+cd.getDate()+" "+months[cd.getMonth()-1]+" "+cd.getFullYear()+" - "+cd.getSeconds()+":"+cd.getMinutes()+":"+cd.getHours()+"] ["+type+"] "+message+" "+parameters) + normalLog("["+cd.getDate()+" "+months[cd.getMonth()-1]+" "+cd.getFullYear()+" - "+cd.getSeconds()+":"+cd.getMinutes()+":"+cd.getHours()+"] ["+ptype+"] "+message+" "+parameters) } \ No newline at end of file diff --git a/core/reactionRoles.js b/core/reactionRoles.js index 83c0bf9..31b619e 100644 --- a/core/reactionRoles.js +++ b/core/reactionRoles.js @@ -6,6 +6,8 @@ const log = bot.errorLog.log const l = bot.language const storage = bot.storage +const APIEvents = require("./api/modules/events") + module.exports = async () => { const chalk = await (await import("chalk")).default @@ -34,23 +36,33 @@ module.exports = async () => { 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()) }) + }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()) } }) } diff --git a/core/ticketCloser.js b/core/ticketCloser.js index 16b7f29..9654066 100755 --- a/core/ticketCloser.js +++ b/core/ticketCloser.js @@ -5,37 +5,63 @@ const config = bot.config const log = bot.errorLog.log const l = bot.language const storage = bot.storage +const permsChecker = require("./utils/permisssionChecker") + +exports.runThis = () => { + client.on("interactionCreate",async (interaction) => { + if (!interaction.isButton()) return + if (interaction.customId != "sendTranscript") 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]}) + }) +} /** * - * @param {discord.Interaction} interaction + * @param {discord.GuildMember} member + * @param {discord.TextChannel} channel * @param {String} prefix * @param {"delete"|"close"|"deletenotranscript"} mode */ -exports.closeTicket = async (interaction,prefix,mode) => { +exports.NEWcloseTicket = async (member,channel,prefix,mode) => { + const guild = channel.guild + const user = member.user const chalk = await (await import("chalk")).default - const channelmessages = await interaction.channel.messages.fetch() - const channel = interaction.channel + const channelmessages = await channel.messages.fetch() - channelmessages.sweep((msgSweep) => { - return msgSweep.author.id == client.user.id - }) + //start code - /** - * @type {String} ticketuserarray - */ - const ticketuserarray = interaction.channel.name - const ticketusername = ticketuserarray.split(prefix)[1] + //remove ot bot from transcript + channelmessages.sweep((msgSweep) => {return msgSweep.author.id == client.user.id}) - var getuserID = storage.get("userTicketStorage",interaction.channel.id) + /**@type {String}*/ + const channelname = channel.name + const ticketOpenerChannelName = channelname.split(prefix)[1] + + //get user that opened the ticket + var getuserID = storage.get("userTicketStorage",channel.id) try { - var getusernameStep1 = client.users.cache.find(u => u.id === getuserID) + var ticketOpener = client.users.cache.find(u => u.id === getuserID) var isDatabaseError = false - }catch{ - var isDatabaseError = true - } + }catch{var isDatabaseError = true} - if (!getusernameStep1){ + if (!ticketOpener){ console.log(chalk.red("[database error]"),"something went wrong when getting the data in the database.\nNo panic, this error fixes itself!") var isDatabaseError = true } @@ -44,22 +70,23 @@ exports.closeTicket = async (interaction,prefix,mode) => { var deleteRequired = false if (mode == "delete"){ - const permsmember = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (config.main_adminroles.some((item)=>{return permsmember.roles.cache.has(item)}) == false && !permsmember.permissions.has("Administrator") && !permsmember.permissions.has("ManageGuild")){ - try { - return interaction.member.send({embeds:[bot.errorLog.noPermsMessage]}) - }catch{ - return interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) - } - } + //delete + //check perms + if (!guild) return + if (!permsChecker.command(user.id,guild.id)){ + permsChecker.sendUserNoPerms(user) + return + } + + //start delete proccess deleteRequired = true - await interaction.channel.send({content:"**"+l.messages.gettingdeleted+"**"}) - log("system","deleted a ticket",[{key:"user",value:interaction.user.tag},{key:"ticket",value:interaction.channel.name}]) + 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) - //getID & send DM - await interaction.channel.messages.fetchPinned().then(msglist => { + //getID & send DM & send api event + await channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false @@ -67,7 +94,7 @@ exports.closeTicket = async (interaction,prefix,mode) => { const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] const ticketData = require("./getoptions").getOptionsById("newT"+ticketId) - require("./api/modules/events").onTicketDelete(interaction.user,interaction.channel,interaction.guild,new Date(),{name:interaction.channel.name,status:"deleted",ticketOptions:ticketData}) + require("./api/modules/events").onTicketDelete(user,channel,guild,new Date(),{name:channel.name,status:"deleted",ticketOptions:ticketData}) if (!firstmsg.embeds[0].author) return false const id = firstmsg.embeds[0].author.name @@ -76,42 +103,90 @@ exports.closeTicket = async (interaction,prefix,mode) => { try{ if (config.system.enable_DM_Messages){ - interaction.member.send({embeds:[bot.errorLog.custom(l.messages.deletedTicketDmTitle,l.messages.deletedTicketDmDescription,":ticket:",config.main_color)]}) + member.send({embeds:[bot.errorLog.custom(l.messages.deletedTicketDmTitle,l.messages.deletedTicketDmDescription,":ticket:",config.main_color)]}) } } catch{log("system","can't send DM to member, member doesn't allow dm's")} }) }else if (mode == "close"){ - + //close + //check perms if (config.system.closeMode == "adminonly"){ - const permsmember = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (config.main_adminroles.some((item)=>{return permsmember.roles.cache.has(item)}) == false && !permsmember.permissions.has("Administrator") && !permsmember.permissions.has("ManageGuild")){ - try { - return interaction.member.send({embeds:[bot.errorLog.noPermsMessage]}) - }catch{ - return interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) - } + if (!guild) return + if (!permsChecker.command(user.id,guild.id)){ + permsChecker.sendUserNoPerms(user) + return } } + //set new permissions var permissionArray = [] const pfb = discord.PermissionFlagsBits if (!isDatabaseError) permissionArray.push({ - id:getusernameStep1, + id:ticketOpener, type:"member", allow:[pfb.ViewChannel], deny:[pfb.AddReactions,pfb.AttachFiles,pfb.EmbedLinks,pfb.SendMessages] }) permissionArray.push({ - id:interaction.guild.roles.everyone, + id:guild.roles.everyone, type:"role", deny:[pfb.AddReactions,pfb.AttachFiles,pfb.EmbedLinks,pfb.SendMessages,pfb.ViewChannel] }) - interaction.channel.permissionOverwrites.set(permissionArray) + //add main adminroles + config.main_adminroles.forEach((role,index) => { + try { + const adminrole = guild.roles.cache.find(r => r.id == role) + if (!adminrole) return + + permissionArray.push({ + id:adminrole, + type:"role", + allow:[pfb.AddReactions,pfb.AttachFiles,pfb.EmbedLinks,pfb.SendMessages,pfb.ViewChannel] + }) + }catch{ + log("system","invalid role! At 'config.json => main_adminroles:"+index) + } + }) + + //add ticket adminroles + await channel.messages.fetchPinned().then(msglist => { + var firstmsg = msglist.last() + + 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) + + if (!ticketData) return + + /** + * @type {String[]} + */ + const ticketadmin = ticketData.adminroles + ticketadmin.forEach((role,index) => { + if (!config.main_adminroles.includes(role)){ + try { + const adminrole = guild.roles.cache.find(r => r.id == role) + if (!adminrole) return + + permissionArray.push({ + id:adminrole, + type:"role", + allow:[pfb.AddReactions,pfb.ViewChannel], + deny:[pfb.AttachFiles,pfb.EmbedLinks,pfb.SendMessages] + }) + }catch{ + log("system","invalid role! At 'config.json => options/ticket/...:"+index) + } + } + }) + }) + + channel.permissionOverwrites.set(permissionArray) //message var closeButtonRow = new discord.ActionRowBuilder() @@ -144,20 +219,20 @@ exports.closeTicket = async (interaction,prefix,mode) => { .setColor(config.main_color) .setTitle(":lock: "+l.messages.closedTitle+" :lock:") .setDescription(l.messages.closedDescription) - interaction.channel.send({embeds:[embed],components:[closeButtonRow]}) + channel.send({embeds:[embed],components:[closeButtonRow]}) - log("system","closed a ticket",[{key:"user",value:interaction.user.tag},{key:"ticket",value:interaction.channel.name}]) + log("system","closed a ticket",[{key:"user",value:user.tag},{key:"ticket",value:channel.name}]) - //getID & send DM - await interaction.channel.messages.fetchPinned().then(msglist => { + //getID & send DM & send api event + await channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() 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) - require("./api/modules/events").onTicketClose(interaction.user,interaction.channel,interaction.guild,new Date(),{name:interaction.channel.name,status:"closed",ticketOptions:ticketData}) + require("./api/modules/events").onTicketClose(user,channel,guild,new Date(),{name:channel.name,status:"closed",ticketOptions:ticketData}) const id = firstmsg.embeds[0].author.name @@ -165,7 +240,7 @@ exports.closeTicket = async (interaction,prefix,mode) => { try{ if (config.system.enable_DM_Messages){ - interaction.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,":ticket:",config.main_color)]}) } } catch{log("system","can't send DM to member, member doesn't allow dm's")} @@ -173,22 +248,24 @@ exports.closeTicket = async (interaction,prefix,mode) => { }else if (mode == "deletenotranscript"){ + //delete with no transcript + //check perms + if (!guild) return + if (!permsChecker.command(user.id,guild.id)){ + permsChecker.sendUserNoPerms(user) + return + } - const permsmember = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (config.main_adminroles.some((item)=>{return permsmember.roles.cache.has(item)}) == false && !permsmember.permissions.has("Administrator") && !permsmember.permissions.has("ManageGuild")){ - interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) - return - } - + //start delete proccess enableTranscript = false deleteRequired = true - interaction.channel.send({content:"**"+l.messages.gettingdeleted+"**"}) - log("system","deleted a ticket",[{key:"user",value:interaction.user.tag},{key:"ticket",value:interaction.channel.name}]) + 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) - //getID & send DM - await interaction.channel.messages.fetchPinned().then(msglist => { + //getID & send DM & send api event + await channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false @@ -196,7 +273,7 @@ exports.closeTicket = async (interaction,prefix,mode) => { const ticketId = firstmsg.embeds[0].footer.text.split("Ticket Type: ")[1] const ticketData = require("./getoptions").getOptionsById("newT"+ticketId) - require("./api/modules/events").onTicketDelete(interaction.user,interaction.channel,interaction.guild,new Date(),{name:interaction.channel.name,status:"deleted",ticketOptions:ticketData}) + require("./api/modules/events").onTicketDelete(user,channel,guild,new Date(),{name:channel.name,status:"deleted",ticketOptions:ticketData}) const id = firstmsg.embeds[0].author.name @@ -204,7 +281,7 @@ exports.closeTicket = async (interaction,prefix,mode) => { try{ if (config.system.enable_DM_Messages){ - interaction.member.send({embeds:[bot.errorLog.custom(l.messages.deletedTicketDmTitle,l.messages.deletedTicketDmDescription,":ticket:",config.main_color)]}) + member.send({embeds:[bot.errorLog.custom(l.messages.deletedTicketDmTitle,l.messages.deletedTicketDmDescription,":ticket:",config.main_color)]}) } } catch{log("system","can't send DM to member, member doesn't allow dm's")} @@ -224,11 +301,11 @@ exports.closeTicket = async (interaction,prefix,mode) => { const transcriptEmbed = new discord.EmbedBuilder() .setColor(config.main_color) .setTitle(l.messages.newTranscriptTitle) - .setAuthor({name:interaction.user.username,iconURL:interaction.user.displayAvatarURL({format:"png"})}) + .setAuthor({name:user.username,iconURL:user.displayAvatarURL({format:"png"})}) .setDescription(l.messages.newTranscriptDescription) - .setFooter({text:"ticket: "+ticketuserarray}) + .setFooter({text:"ticket: "+channelname}) - interaction.guild.channels.cache.find(c => c.id == config.system.transcript_channel).send({ + guild.channels.cache.find(c => c.id == config.system.transcript_channel).send({ embeds:[transcriptEmbed], files:[fileattachment] }) @@ -239,9 +316,9 @@ exports.closeTicket = async (interaction,prefix,mode) => { .setColor(config.main_color) .setTitle(l.messages.newTranscriptTitle) .setDescription(l.messages.newTranscriptDescription) - .setFooter({text:"ticket: "+ticketuserarray}) + .setFooter({text:"ticket: "+channelname}) - if (!isDatabaseError) getusernameStep1.send({ + if (!isDatabaseError) ticketOpener.send({ embeds:[transcriptEmbed], files:[fileattachment] }) @@ -253,31 +330,6 @@ exports.closeTicket = async (interaction,prefix,mode) => { setTimeout(() => {resolve(true)},7000) })} await timer() - await interaction.channel.delete() + await channel.delete() } -} - -exports.runThis = () => { - client.on("interactionCreate",async (interaction) => { - if (!interaction.isButton()) return - if (interaction.customId != "sendTranscript") 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/ticketMessageEmbed.js b/core/ticketMessageEmbed.js index d1e0e8b..bcc9d39 100644 --- a/core/ticketMessageEmbed.js +++ b/core/ticketMessageEmbed.js @@ -33,11 +33,16 @@ exports.createEmbed = (id) => { //----------------------------------- //create the embed const embed = new discord.EmbedBuilder() - .setColor(data.color) .setTitle(data.name) if (data.enableFooter) embed.setFooter({text:data.footer}) if (data.enableThumbnail) embed.setThumbnail(data.thumbnail) + if (data.enableCustomColor){ + embed.setColor(data.color) + }else{ + embed.setColor(config.main_color) + } + var description = data.description if (data.enableTicketExplaination){ description = description+"\n\n__"+l.messages.chooseCategory+"__\n" @@ -90,7 +95,4 @@ exports.createEmbed = (id) => { */ const returnedData = {embed:embed,componentRows:componentRows} return returnedData -} - - -this.createEmbed() \ No newline at end of file +} \ No newline at end of file diff --git a/core/ticketReopener.js b/core/ticketReopener.js index 55d002d..3ebd39f 100755 --- a/core/ticketReopener.js +++ b/core/ticketReopener.js @@ -92,6 +92,51 @@ 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}) + } + + + //NORMAL WAY client.on("interactionCreate",(interaction) => { if (!interaction.isButton()) return @@ -126,38 +171,7 @@ module.exports = () => { interaction.message.edit({embeds:[embed],components:[closeRowNormal]}) - log("system","re-opened a ticket",[{key:"ticket",value:interaction.channel.name},{key:"user",value:interaction.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:interaction.guild.roles.everyone, - type:"role", - allow:everyoneAllowPerms, - deny:everyoneDenyPerms - }) - - interaction.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:[] - }) - } - }) - - interaction.channel.permissionOverwrites.set(permissionsArray) + reopenTicket(interaction.guild,interaction.channel,interaction.user) }) @@ -193,97 +207,6 @@ module.exports = () => { interaction.message.edit({content:null,embeds:[embed],components:[closeRowNormal]}) - log("system","re-opened a ticket",[{key:"ticket",value:interaction.channel.name},{key:"user",value:interaction.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:interaction.guild.roles.everyone, - type:"role", - allow:everyoneAllowPerms, - deny:everyoneDenyPerms - }) - - interaction.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:[] - }) - } - }) - - interaction.channel.permissionOverwrites.set(permissionsArray) - - //getID & send DM - interaction.channel.messages.fetchPinned().then(msglist => { - var firstmsg = msglist.last() - - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false - - const id = firstmsg.embeds[0].author.name - - if (!id) return false - - try{ - if (config.system.enable_DM_Messages){ - interaction.member.send({embeds:[bot.errorLog.custom(l.messages.reopenTicketDmTitle,l.messages.reopenTicketDmDescription,":ticket:",config.main_color)]}) - } - } - catch{log("system","can't send DM to member, member doesn't allow dm's")} - }) + reopenTicket(interaction.guild,interaction.channel,interaction.user) }) - - //DASHBOARD (comming soon!) - /** - * - * @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) - } } \ No newline at end of file diff --git a/core/transcript.js b/core/transcript.js index 2cb6468..4140271 100755 --- a/core/transcript.js +++ b/core/transcript.js @@ -44,6 +44,8 @@ const getUserInfo = (channel) => { exports.createTranscript = async (messagecollection,channel) => { const ticketuserdata = await getUserInfo(channel) + + require("./api/modules/events").onTranscriptCreation(messagecollection,channel,channel.guild,new Date()) try { const cd = new Date() const months = ["January","February","March","April","May","June","July","August","September","October","November","December"] @@ -57,8 +59,8 @@ exports.createTranscript = async (messagecollection,channel) => { if (msg.content){var content = msg.content}else{var content = "*empty message*"} - const msgstats = "files: "+msg.attachments.size+" | embeds: "+msg.embeds.length+" | isbot: "+msg.author.bot - filearray.push("["+timestamp.getDate()+"/"+timestamp.getMonth()+"/"+timestamp.getFullYear()+" | "+timestamp.getHours()+":"+timestamp.getMinutes()+":"+timestamp.getSeconds()+" | "+msg.author.tag+" ] ["+msgstats+"]\n"+content+"\n") + const msgstats = "files: "+msg.attachments.size+", embeds: "+msg.embeds.length + filearray.push("["+timestamp.getDate()+"/"+timestamp.getMonth()+"/"+timestamp.getFullYear()+", "+timestamp.getHours()+":"+timestamp.getMinutes()+":"+timestamp.getSeconds()+"|"+msg.author.tag+"] ["+msgstats+"]\n"+content+"\n") }) if (filearray.length < 2) filearray.push("transcript is empty") diff --git a/core/utils/errorTypes.js b/core/utils/errorTypes.js new file mode 100644 index 0000000..89798fc --- /dev/null +++ b/core/utils/errorTypes.js @@ -0,0 +1,3 @@ +/** + * @typedef {String|Boolean} OTErrorType + */ \ No newline at end of file diff --git a/core/utils/permisssionChecker.js b/core/utils/permisssionChecker.js new file mode 100644 index 0000000..7ae2d02 --- /dev/null +++ b/core/utils/permisssionChecker.js @@ -0,0 +1,76 @@ +const discord = require('discord.js') +const bot = require('../../index') +const client = bot.client +const config = bot.config +const log = bot.errorLog.log +const l = bot.language +const storage = bot.storage + +/** + * + * @param {String} memberid + * @param {String} guildid + * @returns {Boolean} has permissions? + */ +exports.command = (memberid,guildid) => { + const permsmember = client.guilds.cache.find(g => g.id == guildid).members.cache.find(m => m.id == memberid) + if (config.main_adminroles.some((item)=>{return permsmember.roles.cache.has(item)}) == false && !permsmember.permissions.has("Administrator") && !permsmember.permissions.has("ManageGuild")){ + return false + }else {return true} +} + +/** + * + * @param {discord.User} user + * @returns {Boolean} + */ +exports.sendUserNoPerms = (user) => { + try { + user.send({embeds:[bot.errorLog.noPermsMessage]}) + return true + }catch{ + return false + } +} + +/** + * + * @param {discord.User} user + * @returns {Boolean} + */ + exports.sendUserNoTicket = (user) => { + try { + user.send({embeds:[bot.errorLog.notInATicket]}) + return true + }catch{ + return false + } +} + +/** + * + * @param {discord.TextChannel} channel + * @returns {Boolean} + */ + exports.sendChannelNoPerms = (channel) => { + try { + channel.send({embeds:[bot.errorLog.noPermsMessage]}) + return true + }catch{ + return false + } +} + +/** + * + * @param {discord.TextChannel} channel + * @returns {Boolean} + */ + exports.sendChannelNoTicket = (channel) => { + try { + channel.send({embeds:[bot.errorLog.notInATicket]}) + return true + }catch{ + return false + } +} diff --git a/index.js b/index.js index 7d42019..c9ce310 100644 --- a/index.js +++ b/index.js @@ -117,6 +117,9 @@ client.on('ready',async () => { process.exit(1) } } + + //load plugins + require("./core/api/pluginlauncher")() }) if (!isDev){ @@ -148,6 +151,8 @@ if (process.argv[2] && process.argv[2].startsWith("slash")){ } +const APIEvents = require("./core/api/modules/events") + const debugLog = (debugString) => { const content = fs.existsSync("./openticketdebug.txt") ? fs.readFileSync("./openticketdebug.txt").toString() : "==========================\n\n==========================" fs.writeFileSync("./openticketdebug.txt",content+"\nDEBUG: "+debugString) @@ -169,6 +174,8 @@ process.on("uncaughtException",async (error,origin) => { const chalk = await (await import("chalk")).default console.log(chalk.red("\nOPEN TICKET ERROR: ")+error+"\n"+chalk.green("\nCreate a ticket in our support server for more information!\nIf you do this, you might help us to avoid a future bug!\n")) errorLog(error.name+": "+error.message+" | origin: "+origin,error.stack) + + APIEvents.onError(error.name+": "+error.message,new Date()) }) client.login(config.auth_token) \ No newline at end of file diff --git a/language/czech.json b/language/czech.json new file mode 100644 index 0000000..11ce8ef --- /dev/null +++ b/language/czech.json @@ -0,0 +1,79 @@ +{ + "errors":{ + "missingArgsTitle":"Neplatné argumenty", + "missingArgsDescription":"Chybí argumenty", + "noPermsTitle":"Nemáš práva!", + "noPermsDescription":"Nemáš dostatečné práva na tento příkaz!\n Potřebuješ ADMINISTRATOR aby jsi mohl provést příkaz!", + "chooseFromListTitle":"Neplatné ID", + "chooseFromListDescription":"Vyber si z těchto ID:", + "boterror":"Error!", + "notInTicketTitle":"Nejsi v ticketu!", + "notInTicketDescription":"Tento příkaz nefunguje mimo tickety!", + "ticketDoesntExist":"Tento ticket už bohužel neexistuje!", + "roleDoesntExist":"Tato role bohužel neexistuje!", + "anotherOption":"Tato možnost není ticket ale něco jiného!", + "maxAmountTitle":"Maximální počet ticketů dosažen!", + "maxAmountDescription":"Dosáhl jsi maximálního povoleného počtu ticketů!\n Nemůžeš si vytvořit nový!", + "somethingWentWrong":"**Něco je špatně**\nProsím zkus to příště znovu!", + "somethingWentWrongTranscript":"Něco je špatně s transcriptem!**\nProsím zkus to příště znovu!" + }, + "commands":{ + "userAddedTitle":"Uživatel přidán!", + "userAddedDescription":"{0} je přidán do ticketu!", + "userRemovedTitle":"Uživatel odebrán!", + "userRemovedDescription":"{0} je odstraněn z ticketu!", + + "renameTitle":"Jméno bylo změněno!", + "renameWarning":"Varování: jméno kanálu můžeš změnit pouze 2x za minutu!", + + "closeTitle":"Zavři tento ticket!", + "closeDescription":"Můžeš zavřít ticket kliknutím na tlačítko níže!", + "deleteTitle":"Smaž tento ticket!", + "deleteDescription":"Můžeš smazat ticket kliknutím na tlačítko níže!", + "reopenTitle":"Znovu otevři ticket!", + "reopenDescription":"Můžeš znovu otevřít tento ticket kliknutínm na tlačítko níže!", + + "ticketWarning":"The embed is in the message below!", + "maxTicketWarning":"**Varovaní:** _Můžeš si vytvořit použe {0} ticket(s) v jednu chvíli!_" + }, + "helpMenu":{ + "title":"Příkazy:", + "header1":"**Běž {0} vytvořit si ticket!**\n\n", + "header2":"**Použij příkaz `/new` nebo `/ticket` k vytvoření ticketu!**\n\n", + + "msgCmd":"Vytvoř možnost otevírat tickety přes tlačítko. (ADMIN)", + "renameCmd":"Přejmenovat ticket. (Žádné mezery)", + "closeCmd":"Zavři ticket.", + "deleteCmd":"Smaž ticket.", + "addCmd":"Přidej člena do ticketu.", + "removeCmd":"Odebere člena z ticketu.", + "reopenCmd":"Znovu otevři ticket po uzavření." + }, + "buttons":{ + "close":"Zavři ticket", + "delete":"Smaž ticket", + "reopen":"Znovu otevři ticket", + "sendTranscript":"Odešli log ticketu" + }, + "messages":{ + "reopenTitle":"Ticket znovu otevřen!", + "reopenDescription":"Cítím se skvěle že si můžeme zase povídat!", + "closedTitle":"Zavřený ticket!", + "closedDescription":"Pouze admin team zde může nyní komunikovat!\n\n*Klikni na tlačítko níže pro smazání nebo znovu otevření ticketu!*", + "createdTitle":"Ticket vytvořen!", + "createdDescription":"Váš tiket je vytvořen, můžete ho zjistit pomocí pingu!", + + "newTicketDmTitle":"Nový ticket!", + "closedTicketDmTitle":"Ticket uzavřen!", + "deletedTicketDmTitle":"Ticket smazán!", + "closedTicketDmDescription":"Tvůj ticket byl uzavřen!", + "deletedTicketDmDescription":"Tvůj ticket byl smazán!", + "reopenTicketDmTitle":"Ticket znovu otevřen!", + "reopenTicketDmDescription":"Tvůj ticket byl znovu otevřen!", + "newTranscriptTitle":"Nový log ticketu je zde!", + "newTranscriptDescription":"Zde najdeš log svého ticketu!", + "hereIsTheTranscript":"Zde je log:", + + "chooseCategory":"Vyber kategorii:" + } +} \ No newline at end of file diff --git a/package.json b/package.json index b9a475c..407b2d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-ticket", - "version": "2.3.3", + "version": "2.4.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": { @@ -13,6 +13,7 @@ "author": "DJdj Development", "license": "ISC", "dependencies": { + "axios": "^0.27.2", "chalk": "^5.0.1", "discord.js": "^14.0.2", "express": "^4.17.1", diff --git a/plugins/example.plugin.js b/plugins/example.plugin.js new file mode 100644 index 0000000..f892486 --- /dev/null +++ b/plugins/example.plugin.js @@ -0,0 +1,22 @@ +const discord = require("discord.js") +const api = require("../core/api/api.js") + +module.exports = () => { + const {client,config,events,utils,actions} = api + + //this code will run when the bot starts! + + //in this example, we will say "hello" in the console when someone opens a ticket! + + /** + + events.onTicketOpen((user,channel,guild,date,ticketdata) => { + console.log("hello, someone opened a ticket!") + }) + + + */ + + + +} \ No newline at end of file