diff --git a/.gitignore b/.gitignore index 77b939d..4da0179 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,13 @@ node_modules/ package-lock.json devConfig.json -.DS_Store \ No newline at end of file +devConfig1.json +devConfig2.json +devConfig3.json +devConfig4.json +devConfig5.json +.DS_Store +openticketdebug.txt +developerChangelog.md +storage/dynamicDB/ +storage/.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 38e4992..b2f5e32 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ +### large announcement: +[![open moderation](./openmod.png)](https://www.dj-dj.be/projects/open-moderation) + # 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.0.0%20stable-brightgreen.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/releases/tag/v2.0.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.1.0%20stable-brightgreen.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/releases/tag/v2.1.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! @@ -8,21 +11,20 @@ This is an open-source discord ticket bot, you can configure it and it comes wit [![q&a](https://img.shields.io/badge/Q&A-click%20here-blue.svg?style=flat-square)](https://www.github.com/DJj123dj/open-ticket/wiki/q&a) ## features -- discord interaction buttons +- discord buttons - slash & text commands -- close or delete tickets -- translation possible +- close, delete & re-open tickets +- translation (we are searching for translators!) - dynamic database system -- transcripts -- add/remove users from ticket -- custom colors & name +- advanced transcripts +- add/remove users from a ticket +- large embed customisation - create custom ticket names, icons & colors -- create url buttons for websites -- uses discord.js 13 +- create url's & reaction roles! +- uses discord.js v13 - configure your own ticket options -- remove credits if you want +- remove credits if you want (don't do it please ๐Ÿ˜‰) - unlimited tickets at the same time -- localisation in +5 languages (soonโ„ข) ## installation **You need `node.js 16` to run this project!** @@ -44,7 +46,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.0.0) +[click here to view](https://www.github.com/DJj123dj/open-ticket/wiki/config-v2.1.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 @@ -56,7 +58,7 @@ You can also configure your own permissions ## information -_v2.0.0 unstable_ +_v2.1.0 unstable_ changelog: [click here](https://www.github.com/DJj123dj/open-ticket/wiki/Changelog) diff --git a/TEMPDOCS.md b/TEMPDOCS.md deleted file mode 100644 index 4188c3e..0000000 --- a/TEMPDOCS.md +++ /dev/null @@ -1,5 +0,0 @@ -# documentation -The documentation is not available here, go to the [wiki](https://github.com/DJj123dj/open-ticket/wiki) instead. (the wiki isn't fully done yet!) - -## 2.0.0 beta -There is currently no documentation available for open-ticket v2.0.0 beta. So if you want to test it, you need to figure it out on yourself at the moment! \ No newline at end of file diff --git a/commands/add.js b/commands/add.js index 404d198..6d59abd 100644 --- a/commands/add.js +++ b/commands/add.js @@ -2,33 +2,30 @@ 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 module.exports = () => { client.on("messageCreate",msg => { if (!msg.content.startsWith(config.prefix+"add")) return var user = msg.mentions.users.first() - if (!user){ - return msg.channel.send({content:"**There is no user to add:**\nuse: `"+config.prefix+"add `"}) - } + if (!user) return msg.channel.send({embeds:[bot.errorLog.invalidArgsMessage(l.errors.missingArgsDescription+" ``:\n`"+config.prefix+"add `")]}) - if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR")){ - return msg.channel.send({content:"You have no permissions to add someone to the channel!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"}) + if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ + return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) } msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - msg.channel.send({content:"You are not in a ticket!"}) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) msg.channel.permissionOverwrites.create(user.id, { VIEW_CHANNEL:true, ADD_REACTIONS:true,ATTACH_FILES:true, EMBED_LINKS:true, SEND_MESSAGES:true}) - msg.channel.send({content:"Added "+user.tag+" to the ticket"}) - if (config.logs){console.log("[system] added user to ticket (name:"+user.username+",ticket:"+msg.channel.name+")")} + msg.channel.send({embeds:[bot.errorLog.success(l.commands.userAddedTitle,l.commands.userAddedDescription.replace("{0}",user.tag))]}) var loguser = msg.mentions.users.first() - if (config.logs){console.log("[command] "+config.prefix+"add "+loguser.username+" (user:"+msg.author.username+")")} + 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}]) }) }) @@ -37,27 +34,25 @@ module.exports = () => { if (!interaction.isCommand()) return if (interaction.commandName != "add") return const user = interaction.options.getUser("user") - const member = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (!member.permissions.has("MANAGE_CHANNELS") && !member.permissions.has("ADMINISTRATOR")){ - return interaction.reply({content:"You have no permissions to add someone to the channel!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"}) - } + 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("MANAGE_GUILD")){ + interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) + return + } interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - interaction.reply({content:"You are not in a ticket!"}) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) interaction.channel.permissionOverwrites.create(user.id, { VIEW_CHANNEL:true, ADD_REACTIONS:true,ATTACH_FILES:true, EMBED_LINKS:true, SEND_MESSAGES:true}) - interaction.reply({content:"Added "+user.tag+" to the ticket"}) - if (config.logs){console.log("[system] added user to ticket (name:"+user.username+",ticket:"+interaction.channel.name+")")} + interaction.reply({embeds:[bot.errorLog.success(l.commands.userAddedTitle,l.commands.userAddedDescription.replace("{0}",user.tag))]}) var loguser = user - if (config.logs){console.log("[command] "+config.prefix+"add "+loguser.username+" (user:"+interaction.user.username+")")} + 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}]) }) diff --git a/commands/close.js b/commands/close.js index 6e90c86..1a4eb0a 100644 --- a/commands/close.js +++ b/commands/close.js @@ -2,6 +2,8 @@ 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 module.exports = () => { client.on("messageCreate",msg => { @@ -11,10 +13,7 @@ module.exports = () => { msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - msg.channel.send({content:"You are not in a ticket!"}) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) const closebutton = new discord.MessageActionRow() .addComponents([ @@ -25,9 +24,9 @@ module.exports = () => { .setEmoji("๐Ÿ”’") ]) - msg.channel.send({content:"**Click on the button below to close this ticket!**",components:[closebutton]}) + msg.channel.send({embeds:[bot.errorLog.success(l.commands.closeTitle,l.commands.closeDescription)],components:[closebutton]}) - console.log("[system] closed a ticket via command") + log("command","someone used the 'close' command",[{key:"user",value:msg.author.tag}]) }) @@ -41,10 +40,7 @@ module.exports = () => { interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - interaction.reply({content:"You are not in a ticket!"}) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) const closebutton = new discord.MessageActionRow() .addComponents([ @@ -55,9 +51,9 @@ module.exports = () => { .setEmoji("๐Ÿ”’") ]) - interaction.reply({content:"**Click on the button below to close this ticket!**",components:[closebutton]}) + interaction.reply({embeds:[bot.errorLog.success(l.commands.closeTitle,l.commands.closeDescription)],components:[closebutton]}) - console.log("[system] closed a ticket via command") + log("command","someone used the 'close' command",[{key:"user",value:interaction.user.tag}]) }) }) diff --git a/commands/delete.js b/commands/delete.js index f0b7305..e3d8dc5 100644 --- a/commands/delete.js +++ b/commands/delete.js @@ -2,19 +2,21 @@ 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 module.exports = () => { client.on("messageCreate",msg => { if (!msg.content.startsWith(config.prefix+"delete")) return + if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ + return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) + } msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - msg.channel.send({content:"You are not in a ticket!"}) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) const closebutton = new discord.MessageActionRow() .addComponents([ @@ -25,9 +27,9 @@ module.exports = () => { .setEmoji("โŒ") ]) - msg.channel.send({content:"**Click on the button below to delete this ticket!**",components:[closebutton]}) + msg.channel.send({embeds:[bot.errorLog.success(l.commands.deleteTitle,l.commands.deleteDescription)],components:[closebutton]}) - console.log("[system] deleted a ticket via command") + log("command","someone used the 'delete' command",[{key:"user",value:msg.author.tag}]) }) @@ -38,13 +40,16 @@ module.exports = () => { if (!interaction.isCommand()) 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("MANAGE_GUILD")){ + interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) + return + } + interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - interaction.reply({content:"You are not in a ticket!"}) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) const closebutton = new discord.MessageActionRow() .addComponents([ @@ -55,9 +60,9 @@ module.exports = () => { .setEmoji("โŒ") ]) - interaction.reply({content:"**Click on the button below to delete this ticket!**",components:[closebutton]}) + interaction.reply({embeds:[bot.errorLog.success(l.commands.deleteTitle,l.commands.deleteDescription)],components:[closebutton]}) - console.log("[system] deleted a ticket via command") + log("command","someone used the 'close' command",[{key:"user",value:interaction.user.tag}]) }) }) diff --git a/commands/help.js b/commands/help.js index fe5798e..cd34d3d 100644 --- a/commands/help.js +++ b/commands/help.js @@ -2,27 +2,29 @@ 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 module.exports = () => { const helpEmbed = new discord.MessageEmbed() .setColor(config.main_color) - .setTitle("Help Menu:") + .setTitle(l.helpMenu.title) const prefix = config.prefix - const header = config.system.ticket_channel ? "**Go to <#"+config.system.ticket_channel+"> to create a ticket!**\n\n" : "**Run the command `/new` or `/ticket` to create a ticket!**\n\n" - helpEmbed.setDescription(header+"`"+prefix+"msg ` โžœ _Spawn an embed with buttons. (admin only)_\n\n`"+prefix+"rename ` โžœ _Rename a ticket. (no spaces)_\n`"+prefix+"close` โžœ _Close a ticket._\n`"+prefix+"delete` โžœ _Delete a ticket._\n\n`"+prefix+"add ` โžœ _Add a user to the ticket._\n`"+prefix+"remove ` โžœ _Remove a user from the ticket._`") + const header = config.system.ticket_channel ? l.helpMenu.header1.replace("{0}","<#"+config.system.ticket_channel+">") : l.helpMenu.header2 + helpEmbed.setDescription(header+"`"+prefix+"msg ` โžœ _"+l.helpMenu.msgCmd+"_\n\n`"+prefix+"rename ` โžœ _"+l.helpMenu.renameCmd+"_\n`"+prefix+"close` โžœ _"+l.helpMenu.closeCmd+"_\n`"+prefix+"delete` โžœ _"+l.helpMenu.deleteCmd+"_\n`"+prefix+"reopen` โžœ _"+l.helpMenu.reopenCmd+"_\n\n`"+prefix+"add ` โžœ _"+l.helpMenu.addCmd+"_\n`"+prefix+"remove ` โžœ _"+l.helpMenu.removeCmd+"_`") - if (config.credits) helpEmbed.setFooter({text:"Open-Ticket by DJdj Development | view on github for source code"}) + 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"}) client.on("messageCreate",msg => { if (!msg.content.startsWith(config.prefix)) return var args = msg.content.split(config.prefix) - 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")){ + 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]}) - if (config.logs){console.log("[command] "+config.prefix+"ticket help (user:"+msg.author.username+")")} + log("command","someone used the 'help' command",[{key:"user",value:msg.author.tag}]) } }) @@ -31,5 +33,6 @@ module.exports = () => { if (interaction.commandName != "help") return interaction.reply({embeds:[helpEmbed]}) + log("command","someone used the 'help' command",[{key:"user",value:interaction.user.tag}]) }) } \ No newline at end of file diff --git a/commands/remove.js b/commands/remove.js index 7f15655..a60d9d1 100644 --- a/commands/remove.js +++ b/commands/remove.js @@ -2,33 +2,31 @@ 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 module.exports = () => { client.on("messageCreate",msg => { if (!msg.content.startsWith(config.prefix+"remove")) return var user = msg.mentions.users.first() - if (!user){ - return msg.channel.send({content:"**There is no user to remove:**\nuse: `"+config.prefix+"remove `"}) - } + if (!user) return msg.channel.send({embeds:[bot.errorLog.invalidArgsMessage(l.errors.missingArgsDescription+" ``:\n`"+config.prefix+"remove `")]}) - if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR")){ - return msg.channel.send({content:"You have no permissions to remove someone from the channel!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"}) + if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ + return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) } msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - msg.channel.send({content:"You are not in a ticket!"}) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) msg.channel.permissionOverwrites.delete(user.id) - msg.channel.send({content:"Deleted "+user.tag+" from the ticket"}) - if (config.logs){console.log("[system] deleted user from ticket (name:"+user.username+",ticket:"+msg.channel.name+")")} + msg.channel.send({embeds:[bot.errorLog.success(l.commands.userRemovedTitle,l.commands.userRemovedDescription.replace("{0}",user.tag))]}) var loguser = msg.mentions.users.first() - if (config.logs){console.log("[command] "+config.prefix+"remove "+loguser.username+" (user:"+msg.author.username+")")} + + 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}]) }) }) @@ -37,27 +35,27 @@ module.exports = () => { if (!interaction.isCommand()) return if (interaction.commandName != "remove") return const user = interaction.options.getUser("user") - const member = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (!member.permissions.has("MANAGE_CHANNELS") && !member.permissions.has("ADMINISTRATOR")){ - return interaction.reply({content:"You have no permissions to remove someone from the channel!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"}) - } + 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("MANAGE_GUILD")){ + interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) + return + } + interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - interaction.reply({content:"You are not in a ticket!"}) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) interaction.channel.permissionOverwrites.delete(user.id) - interaction.reply({content:"Deleted "+user.tag+" from the ticket"}) - if (config.logs){console.log("[system] removed user from ticket (name:"+user.username+",ticket:"+interaction.channel.name+")")} + interaction.reply({embeds:[bot.errorLog.success(l.commands.userRemovedTitle,l.commands.userRemovedDescription.replace("{0}",user.tag))]}) var loguser = user - if (config.logs){console.log("[command] "+config.prefix+"remove "+loguser.username+" (user:"+interaction.user.username+")")} + + 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}]) }) diff --git a/commands/rename.js b/commands/rename.js index e3333e4..364ee1c 100644 --- a/commands/rename.js +++ b/commands/rename.js @@ -2,6 +2,8 @@ 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 module.exports = () => { client.on("messageCreate",msg => { @@ -10,17 +12,16 @@ module.exports = () => { msg.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - msg.channel.send({content:"You are not in a ticket!"}) - return - } - + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) - if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR")){ - return msg.channel.send({content:"You have no permissions to change the channel name!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"}) + if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ + return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) } var newname = msg.content.split(config.prefix+"rename")[1].substring(1) + + if (!newname) return msg.channel.send({embeds:[bot.errorLog.invalidArgsMessage(l.errors.missingArgsDescription+" ``:\n`"+config.prefix+"rename `")]}) + var name = msg.channel.name var prefix = "" const tickets = config.options @@ -33,9 +34,10 @@ module.exports = () => { if (!prefix) prefix = "noprefix-" msg.channel.setName(prefix+newname) - msg.channel.send({content:"**The name is changed!**\nWarning: you can only change the channel name 2 times per minute! (this is due discord rate limits)"}) + msg.channel.send({embeds:[bot.errorLog.success(l.commands.renameTitle,l.commands.renameWarning)]}) - console.log("[system] renamed a ticket via command") + 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}]) }) @@ -49,14 +51,12 @@ module.exports = () => { interaction.channel.messages.fetchPinned().then(msglist => { var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id){ - interaction.reply({content:"You are not in a ticket!"}) - return - } + if (firstmsg == undefined || firstmsg.author.id != client.user.id)return interaction.reply({embeds:[bot.errorLog.notInATicket]}) - const member = client.guilds.cache.find(g => g.id == interaction.guild.id).members.cache.find(m => m.id == interaction.member.id) - if (!member.permissions.has("MANAGE_CHANNELS") && !member.permissions.has("ADMINISTRATOR")){ - return interaction.reply({content:"You have no permissions to change the channel name!\nYou need the `ADMINISTRATOR` or `MANAGE_CHANNELS` permission"}) + 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("MANAGE_GUILD")){ + interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) + return } var newname = interaction.options.getString("name") @@ -72,9 +72,10 @@ module.exports = () => { if (!prefix) prefix = "noprefix-" interaction.channel.setName(prefix+newname) - interaction.reply({content:"**The name is changed!**\nWarning: you can only change the channel name 2 times per minute! (this is due discord rate limits)"}) + interaction.reply({embeds:[bot.errorLog.success(l.commands.renameTitle,l.commands.renameWarning)]}) - console.log("[system] renamed a ticket via command") + 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 new file mode 100644 index 0000000..87273a0 --- /dev/null +++ b/commands/reopen.js @@ -0,0 +1,51 @@ +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 + +module.exports = () => { + var reopenCommandBar = new discord.MessageActionRow() + .addComponents( + new discord.MessageButton() + .setCustomId("reopenTicket1") + .setDisabled(false) + .setStyle("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]}) + + msg.channel.send({embeds:[bot.errorLog.success(l.commands.reopenTitle,l.commands.reopenDescription)],components:[reopenCommandBar]}) + + + log("command","someone used the 'reopen' command",[{key:"user",value:msg.author.tag}]) + }) + + }) + + client.on("interactionCreate",(interaction) => { + if (!interaction.isCommand()) return + if (interaction.commandName != "reopen") return + + interaction.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]}) + + interaction.reply({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}]) + }) + + + }) +} \ No newline at end of file diff --git a/commands/ticket.js b/commands/ticket.js index f76af3c..d175368 100644 --- a/commands/ticket.js +++ b/commands/ticket.js @@ -2,10 +2,8 @@ const discord = require('discord.js') const bot = require('../index') const client = bot.client const config = bot.config - -/** ============================= - ** NOT READY YET - ** =============================*/ +const log = bot.errorLog.log +const l = bot.language module.exports = () => { /**@type {String[]} */ @@ -16,24 +14,23 @@ module.exports = () => { client.on("messageCreate", msg => { - if (msg.content.startsWith(config.prefix+"msg")){ - if (config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ - msg.channel.send({content:"You have no permission to run this command!"}) - return + if (msg.content.startsWith(config.prefix+"msg"||config.prefix+"message")){ + + if (!msg.member.permissions.has("MANAGE_CHANNELS") && !msg.member.permissions.has("ADMINISTRATOR") && config.main_adminroles.some((item)=>{return msg.member.roles.cache.has(item)}) == false){ + return msg.channel.send({embeds:[bot.errorLog.noPermsMessage]}) } const id = msg.content.split(config.prefix+"msg")[1].substring(1) ? msg.content.split(config.prefix+"msg")[1].substring(1) : false - if (!id) return msg.channel.send({content:"**There is no id!**\nUse: `"+config.prefix+"msg `"}) - if (!msgIds.includes(id)) return msg.channel.send({content:"**Invalid id!**\nChoose from this list:\n_"+msgIds.join("_\n_")+"_"}) + if (!id) return msg.channel.send({embeds:[bot.errorLog.invalidArgsMessage(l.errors.missingArgsDescription+" ``:\n`"+config.prefix+"msg `")]}) + if (!msgIds.includes(id)) return msg.channel.send({embeds:[bot.errorLog.invalidIdChooseFromList(msgIds)]}) const {embed,componentRows} = require("../core/ticketMessageEmbed").createEmbed(id) msg.channel.send({embeds:[embed],components:componentRows}) - if (config.logs){console.log("[command] "+config.prefix+"ticket msg (user:"+msg.author.username+")")} - if (config.logs){console.log("[system] created ticket message")} + log("command","someone used the 'msg' command",[{key:"user",value:msg.author.tag},{key:"id",value:id}]) } }) @@ -41,22 +38,22 @@ module.exports = () => { if (!interaction.isCommand()) return if (interaction.commandName != "message") return - if (config.main_adminroles.some((item)=>{return interaction.guild.members.cache.find((m) => m.id == interaction.member.id).roles.cache.has(item)}) == false){ - interaction.reply({content:"You have no permission to run this command!"}) - 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("MANAGE_GUILD")){ + interaction.reply({embeds:[bot.errorLog.noPermsMessage],ephemeral:true}) + return + } const id = interaction.options.getString("id") - if (!msgIds.includes(id)) return interaction.reply({content:"**Invalid id!**\nChoose from this list:\n_"+msgIds.join("_\n_")+"_"}) + if (!msgIds.includes(id)) return interaction.reply({embeds:[bot.errorLog.invalidIdChooseFromList(msgIds)]}) const {embed,componentRows} = require("../core/ticketMessageEmbed").createEmbed(id) - interaction.reply({content:"The embed is in the message below!"}) + interaction.reply({content:l.commands.ticketWarning}) interaction.channel.send({embeds:[embed],components:componentRows}) - if (config.logs){console.log("[command] "+config.prefix+"ticket msg (user:"+interaction.member.user.username+")")} - if (config.logs){console.log("[system] created ticket message")} + log("command","someone used the 'msg' command",[{key:"user",value:interaction.user.tag},{key:"id",value:id}]) }) } \ No newline at end of file diff --git a/config.json b/config.json index ffc16d0..2c1fa3e 100644 --- a/config.json +++ b/config.json @@ -1,12 +1,11 @@ { "bot_name":"Wumpus", - "main_color":"#fffff", + "main_color":"#ffffff", "server_id":"server id (for slash cmds)", "auth_token":"auth token", "main_adminroles":["discord role id"], "prefix":"!ticket ", - "logs":true, - "languagefile":"english.json (currently not working)", + "languagefile":"english", "credits":true, "status":{ @@ -22,6 +21,7 @@ "has@everyoneaccess":false, "member_role":"member role (doesn't have access to tickets)", + "closeMode":"adminonly|normal", "enable_transcript":false, "enable_DM_transcript":false, @@ -42,7 +42,8 @@ "channelprefix":"question-", "category":"category id", "message":"You created a ticket!", - "enableDMMessage":true + "enableDMMessage":true, + "ticketmessage":"The staff will help you soon!\n\n*Click on the button below to close the ticket!*" }, { @@ -78,10 +79,10 @@ "name":"Choose Your Ticket", "description":"You can click one of the buttons below!\nYou can also customize all the embeds now!", "enableFooter":true, - "footer":"Open Ticket v2.0.0 beta - sneakpeak", + "footer":"Open Ticket v2.1.0 - I'm a footer!", "enableThumbnail":false, "thumbnail":"https://www.example.com/catmemes/cat.png", - "color":"#0075e9", + "color":"#ffffff", "options":["general","apply"], "enableTicketExplaination":true, "enableMaxTicketsWarning":true diff --git a/core/checker.js b/core/checker.js index fc17c58..83e6e6a 100644 --- a/core/checker.js +++ b/core/checker.js @@ -47,9 +47,18 @@ exports.checker = async () => { } /**@param {String} value @param {String} path */ - const checkColor = (value,path) => { - if (!/^#[a-f0-9]{6}$/.test(value)){ - createError("'"+path+"' | invalid color!") + const checkHexColor = (value,path) => { + if (!/^#[a-fA-F0-9]{3,6}$/.test(value)){ + if (value.length < 4) return createError("'"+path+"' | hex color too short! (example: #123abc)") + if (value.length > 7) return createError("'"+path+"' | hex color too long! (example: #123abc)") + createError("'"+path+"' | invalid color! (example: #123abc)") + } + } + + /**@param {String} value @param {String} path */ + const checkEmbedColor = (value,path) => { + if (!['DEFAULT','WHITE','AQUA','GREEN','BLUE','YELLOW','PURPLE','LUMINOUS_VIVID_PINK','FUCHSIA','GOLD','ORANGE','RED','GREY','DARKER_GREY','NAVY','DARK_AQUA','DARK_GREEN','DARK_BLUE','DARK_PURPLE','DARK_VIVID_PINK','DARK_GOLD','DARK_ORANGE','DARK_RED','DARK_GREY','LIGHT_GREY','DARK_NAVY','BLURPLE','GREYPLE','DARK_BUT_NOT_BLACK','NOT_QUITE_BLACK','RANDOM'].includes(value)){ + return createError("'"+path+"' | invalid color, must be a hex code or default color (more info in the wiki)") } } @@ -123,13 +132,15 @@ exports.checker = async () => { createError("'"+path+"/id' | option id can't contain space characters!") } if (option.id.length > 20){ - createError("'"+path+"/id' | option id max lenght is 20") + createError("'"+path+"/id' | option id max lenght is 20!") } //name checkType(option.name,"string",path+"/name") if (option.name.length > 100){ createWarn("'"+path+"/name' | if your name is too long it maybe doesn't look so good!") + }else if (option.name.length < 1){ + createError("'"+path+"/name' | there is no name!") } //description @@ -177,13 +188,19 @@ exports.checker = async () => { //category checkType(option.category,"string",path+"/category") - checkDiscord("categoryid",option.category,path+"/category") + if (option.category.length > 0){ + checkDiscord("categoryid",option.category,path+"/category") + } //message checkType(option.message,"string",path+"/message") //enableDMmessage checkType(option.enableDMMessage,"boolean",path+"/enableDMMessage") + + //ticketmessage + checkType(option.ticketmessage,"string",path+"/ticketmessage") + }else if (type == "website"){ //url checkType(option.url,"string",path+"/url") @@ -218,8 +235,17 @@ exports.checker = async () => { } } - //checker - var configArray = ["bot_name","main_color","server_id","auth_token","main_adminroles","prefix","logs","languagefile","credits","status","system","options","messages"] + const checkMessage = (input,path) => { + + } + + //--------------------------| + //--------------------------| + //checker => START HERE | + //--------------------------| + //--------------------------| + + var configArray = ["bot_name","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") @@ -229,13 +255,21 @@ exports.checker = async () => { checkType(config.bot_name,"string","bot_name") - checkColor(config.main_color,"main_color") + if (config.main_color.startsWith("#")){ + checkHexColor(config.main_color,"main_color") + }else{ + checkEmbedColor(config.main_color,"main_color") + } checkDiscord("serverid",config.server_id,"server_id") checkToken(config.auth_token) checkDiscordArray("roleid",config.main_adminroles,"main_adminroles") checkString(config.prefix,1,15,"prefix","prefix") - checkType(config.logs,"boolean","logs") - //languagefile (comming soon) + //languagefile + checkType(config.languagefile,"string","languagefile") + const lf = config.languagefile + if (!lf.startsWith("custom") && !lf.startsWith("english") && !lf.startsWith("dutch") && !lf.startsWith("romanian")){ + createError("'languagefile' | invalid language, more info in the wiki") + } checkType(config.credits,"boolean","credits") @@ -263,6 +297,12 @@ exports.checker = async () => { if (config.system.member_role != "" && config.system.member_role != " " && config.system.member_role != "false" && config.system.member_role != "null" && config.system.member_role != "0"){ checkDiscord("roleid",config.system.member_role,"system/member_role") } + checkType(config.system.closeMode,"string","system/closeMode") + if (!["normal","adminonly"].includes(config.system.closeMode)){ + createError("'system/closeMode' | the close mode must be adminonly or normal") + } + console.log("hoi") + checkType(config.system.enable_transcript,"boolean","system/enable_transcript") checkType(config.system.enable_DM_transcript,"boolean","system/enable_DM_transcript") if (config.system.enable_transcript){ diff --git a/core/closebuttons.js b/core/closebuttons.js index 1f1c903..cec9b40 100644 --- a/core/closebuttons.js +++ b/core/closebuttons.js @@ -2,6 +2,7 @@ const discord = require('discord.js') const bot = require('../index') const client = bot.client const config = bot.config +const l = bot.language module.exports = () => { @@ -58,7 +59,7 @@ module.exports = () => { .setCustomId("closeTicket") .setDisabled(false) .setStyle("SECONDARY") - .setLabel("Close Ticket") + .setLabel(l.buttons.close) .setEmoji("๐Ÿ”’") ) .addComponents( @@ -66,7 +67,7 @@ module.exports = () => { .setCustomId("deleteTicket") .setDisabled(false) .setStyle("DANGER") - .setLabel("Delete Ticket") + .setLabel(l.buttons.delete) .setEmoji("โœ–๏ธ") ) var closeRowClosed = new discord.MessageActionRow() @@ -75,7 +76,7 @@ module.exports = () => { .setCustomId("deleteTicket1") .setDisabled(false) .setStyle("DANGER") - .setLabel("Delete Ticket") + .setLabel(l.buttons.delete) .setEmoji("โœ–๏ธ") ) .addComponents( @@ -83,9 +84,35 @@ module.exports = () => { .setCustomId("sendTranscript") .setDisabled(false) .setStyle("SECONDARY") - .setLabel("Send Transcript File") + .setLabel(l.buttons.sendTranscript) .setEmoji("๐Ÿ“„") ) + .addComponents( + new discord.MessageButton() + .setCustomId("reopenTicket") + .setDisabled(false) + .setStyle("SUCCESS") + .setLabel(l.buttons.reopen) + .setEmoji("โœ”") + ) + + var closeRowDisabled = new discord.MessageActionRow() + .addComponents( + new discord.MessageButton() + .setCustomId("closeTicket") + .setDisabled(true) + .setStyle("SECONDARY") + .setLabel(l.buttons.close) + .setEmoji("๐Ÿ”’") + ) + .addComponents( + new discord.MessageButton() + .setCustomId("deleteTicket") + .setDisabled(true) + .setStyle("DANGER") + .setLabel(l.buttons.delete) + .setEmoji("โœ–๏ธ") + ) //NORMAL CLOSE @@ -109,7 +136,16 @@ module.exports = () => { if (interaction.customId != "closeTicketTrue") return interaction.deferUpdate() - interaction.message.edit({components:[closeRowClosed]}) + + 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("MANAGE_GUILD")){ + interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) + return + } + } + + interaction.message.edit({components:[closeRowDisabled]}) /** * @type {String} @@ -131,6 +167,15 @@ module.exports = () => { if (interaction.customId != "closeTicketTrue1") return interaction.deferUpdate() + + 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("MANAGE_GUILD")){ + interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) + return + } + } + const closedButtonDisabled = new discord.MessageActionRow() .addComponents([ new discord.MessageButton() @@ -141,6 +186,10 @@ module.exports = () => { ]) interaction.message.edit({components:[closedButtonDisabled]}) + interaction.channel.messages.fetchPinned().then((messages) => { + messages.first().edit({components:[closeRowDisabled]}) + }) + /** * @type {String} */ @@ -179,6 +228,12 @@ module.exports = () => { interaction.deferUpdate() + 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("MANAGE_GUILD")){ + interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) + return + } + /** * @type {String} */ @@ -219,6 +274,12 @@ module.exports = () => { interaction.deferUpdate() + 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("MANAGE_GUILD")){ + interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) + return + } + /** * @type {String} */ diff --git a/core/dynamicdatabase/cleardata.js b/core/dynamicdatabase/cleardata.js index c63acfd..be11d68 100644 --- a/core/dynamicdatabase/cleardata.js +++ b/core/dynamicdatabase/cleardata.js @@ -23,14 +23,14 @@ ask() const runClear = async () => { const chalk = await (await import("chalk")).default - console.log(chalk.blue("You can get a node.js warning below, just ignore that, it's not important!")) + //console.log(chalk.blue("You can get a node.js warning below, just ignore that, it's not important!")) const dataPaths = ["./storage/dynamicDB"] var index = 0 dataPaths.forEach((path) => { try { - fs.rmdirSync(path,{recursive:true,force:true}) + fs.rmSync(path,{recursive:true,force:true}) }catch{ //console.log(path,"doesn't exist") } diff --git a/core/dynamicdatabase/storage.js b/core/dynamicdatabase/storage.js index 7405466..7fa0482 100644 --- a/core/dynamicdatabase/storage.js +++ b/core/dynamicdatabase/storage.js @@ -17,16 +17,16 @@ 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 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 diff --git a/core/errorLogSystem.js b/core/errorLogSystem.js new file mode 100644 index 0000000..c9476f9 --- /dev/null +++ b/core/errorLogSystem.js @@ -0,0 +1,117 @@ +const discord = require('discord.js') +const bot = require('../index') +const client = bot.client +const config = bot.config +const l = bot.language + +const loadChalk = async () => { + return await (await import("chalk")).default +} +const embed = discord.MessageEmbed + +exports.noPermsMessage = new embed() + .setColor("RED") + .setTitle(":x: "+l.errors.noPermsTitle+" :x:") + .setDescription(l.errors.noPermsDescription) + +/**@param {String} message */ +exports.invalidArgsMessage = (message) => { + var x = new embed() + .setColor("RED") + .setTitle(":x: "+l.errors.missingArgsTitle+" :x:") + .setDescription(message) + + return x +} + +/**@param {String} message */ +exports.serverError = (message) => { + var x = new embed() + .setColor("ORANGE") + .setTitle(":warning: "+l.errors.boterror+" :warning:") + .setDescription(message) + + return x +} + +/**@param {String[]} list */ +exports.invalidIdChooseFromList = (list) => { + var x = new embed() + .setColor("RED") + .setTitle(":x: "+l.errors.chooseFromListTitle+" :x:") + .setDescription(l.errors.chooseFromListDescription+"\n`"+list.join("`\n`")+"`") + return x +} + +exports.notInATicket = new embed() + .setColor("RED") + .setTitle(":x: "+l.errors.notInTicketTitle+" :x:") + .setDescription(l.errors.notInTicketDescription) + + +/**@param {String} message @param {String} title */ +exports.success = (title,message) => { + var x = new embed() + .setColor(config.main_color) + .setTitle(":white_check_mark: "+title+" :white_check_mark:") + .setDescription(message) + + return x +} + +/**@param {String} message @param {String} title */ +exports.warning = (title,message) => { + var x = new embed() + .setColor("ORANGE") + .setTitle(":warning: "+title+" :warning:") + .setDescription(message) + + return x +} + +/**@param {String} message the message @param {String} title the title @param {String} emoji an discord emoji @param {discord.ColorResolvable} color the embed color*/ +exports.custom = (title,message,emoji,color) => { + var x = new embed() + .setColor(color) + .setTitle(emoji+" "+title+" "+emoji) + .setDescription(message) + + return x +} + +const normalLog = (debugString) => { + const fs = require("fs") + const content = fs.existsSync("./openticketdebug.txt") ? fs.readFileSync("./openticketdebug.txt").toString() : "==========================\n\n==========================" + fs.writeFileSync("./openticketdebug.txt",content+"\nSYSTEM: "+debugString) +} + +/** + * + * @param {"system"|"command"|"info"} type + * @param {String} message + * @param {[{key:String,value:String}]} params + */ +exports.log = async (type,message,params) => { + const chalk = await loadChalk() + var paramstring = "" + if (params){ + if (params.length > 0){ + params.forEach((p) => { + paramstring = paramstring+p.key+": "+p.value+" " + }) + } + } + const parameters = params ? "("+paramstring+")" : " " + + if (type == "command"){ + console.log(chalk.green("[command] ")+message+" "+chalk.yellow(parameters)) + }else if (type == "info"){ + console.log(chalk.blue("[info] ")+message+" "+chalk.yellow(parameters)) + }else if (type == "system"){ + console.log(chalk.green("[system] ")+message+" "+chalk.yellow(parameters)) + } + + 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) +} \ No newline at end of file diff --git a/core/getoptions.js b/core/getoptions.js index a8a7744..ada3a01 100644 --- a/core/getoptions.js +++ b/core/getoptions.js @@ -3,7 +3,7 @@ const config = bot.config /** * @param {Number} index - * @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"adminroles"|"channelprefix"|"category"|"message"|"enableDMMessage"} value + * @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"adminroles"|"channelprefix"|"category"|"message"|"enableDMMessage"|"ticketmessage"} value */ exports.getTicketValue = (index,value) => { if (value == "id"){ @@ -29,7 +29,7 @@ exports.getRoleValue = (index,value) => { } /** - * @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"adminroles"|"channelprefix"|"category"|"message"|"enableDMMessage"} value + * @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"adminroles"|"channelprefix"|"category"|"message"|"enableDMMessage"|"ticketmessage"} value */ exports.getTicketValues = (value) => { var result = [] @@ -55,7 +55,7 @@ exports.getRoleValue = (index,value) => { } /** - * @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"roles"|"mode"|"enableDMMessage"} value + * @param {"id"|"name"|"description"|"icon"|"label"|"type"|"color"|"roles"|"mode"|"enableDMMessage""} value */ exports.getRoleValues = (value) => { var result = [] @@ -79,6 +79,7 @@ class TicketOptions { this.category = "" this.message = "" this.enableDMMessage = true + this.ticketmessage = "" } } /** @@ -110,5 +111,6 @@ exports.exportedOptionClass = class { this.category = "" this.message = "" this.enableDMMessage = true + this.ticketmessage = "" } } \ No newline at end of file diff --git a/core/languageManager.js b/core/languageManager.js new file mode 100644 index 0000000..b39b8b4 --- /dev/null +++ b/core/languageManager.js @@ -0,0 +1,37 @@ +const index = require("../index") + +if (index.developerMode){ + var config = require("../devConfig.json") +}else{var config = require("../config.json")} + + +var localLanguage = require("../language/english.json") +if (config.languagefile.startsWith("custom")) localLanguage = require("../language/custom.json") +else if (config.languagefile.startsWith("dutch")) localLanguage = require("../language/dutch.json") +else if (config.languagefile.startsWith("english")) localLanguage = require("../language/english.json") +else if (config.languagefile.startsWith("deutsch")) localLanguage = require("../language/deutsch.json") +else if (config.languagefile.startsWith("french")) localLanguage = require("../language/french.json") +else if (config.languagefile.startsWith("romanian")) localLanguage = require("../language/romanian.json") + +const errorLog = async () => { + const chalk = await (await import("chalk")).default + + console.log(chalk.red("Something went wrong when loading the language!")+"\nCheck the config file or create a ticket in our server!") +} + +const successLog = async (language) => { + const chalk = await (await import("chalk")).default + + console.log(chalk.green("loaded language "+language+"...")) +} + +if (!localLanguage){ + const runError = async () => { + await errorLog() + process.exit(1) + } + runError() +}else{ + exports.language = localLanguage + successLog(config.languagefile) +} \ No newline at end of file diff --git a/core/reactionRoles.js b/core/reactionRoles.js index 0e288b4..651d2d5 100644 --- a/core/reactionRoles.js +++ b/core/reactionRoles.js @@ -2,7 +2,8 @@ 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 module.exports = async () => { @@ -14,12 +15,13 @@ module.exports = async () => { interaction.deferUpdate() - const optionid = interaction.customId.split("newR")[1] - if (!optionid){ - interaction.reply({content:"This button doesn't exist anymore"}) - return + if (interaction.customId.startsWith("newR")){ + const optionid = interaction.customId.split("newR")[1] + if (!optionid){ + interaction.reply({embeds:[bot.errorLog.serverError(l.errors.roleDoesntExist)]}) + return + } } - try { const option = require("./utils/getButton").getOption(optionid) @@ -30,27 +32,31 @@ module.exports = async () => { if (mode == "add"){ option.roles.forEach((role) => { interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role) - console.log("[system] added role",role,"to",user.user.tag) + + log("system","added role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) }) }else if (mode == "remove"){ option.roles.forEach((role) => { interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role) - console.log("[system] removed role",role,"from",user.user.tag) + + log("system","removed role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) }) }else if (mode == "add&remove"){ option.roles.forEach((role) => { if (interaction.guild.members.cache.find(u => u.id == user.id).roles.cache.has(role)){ interaction.guild.members.cache.find(u => u.id == user.id).roles.remove(role) - console.log("[system] removed role",role,"from",user.user.tag) + + log("system","added role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) }else { interaction.guild.members.cache.find(u => u.id == user.id).roles.add(role) - console.log("[system] added role",role,"to",user.user.tag) + + log("system","removed role (reaction roles)",[{key:"user",value:interaction.user.tag},{key:"role",value:role}]) } }) } }catch{ - interaction.reply({ephemeral:true,content:"Something went wrong! Contact the owner of this bot for more information"}) + interaction.replyinteraction.channel.send({embeds:[bot.errorLog.serverError(l.errors.somethingWentWrong)]}) } }) } \ No newline at end of file diff --git a/core/slashSystem/slashEnable.js b/core/slashSystem/slashEnable.js index 7fbb6bb..446de3d 100644 --- a/core/slashSystem/slashEnable.js +++ b/core/slashSystem/slashEnable.js @@ -13,7 +13,9 @@ module.exports = async () => { var choices = [] ids.forEach((id) => { const option = getoptions.getOptionsById(id) - choices.push({name:option.name,value:option.id}) + if (option.type == "ticket"){ + choices.push({name:option.name,value:option.id}) + } }) /**@type {[{name:String,value:String}]} */ @@ -24,11 +26,11 @@ module.exports = async () => { var readystats = 0 - process.stdout.write("[status] there are "+chalk.blue("0 out of 9")+" 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)") - if (readystats >= 9){ + if (readystats >= 10){ console.log(chalk.green("\nready!")) console.log(chalk.bgBlue("you can now start the bot with 'npm start'!")) process.exit(1) @@ -179,4 +181,14 @@ module.exports = async () => { readystats++ }) + //reopen + client.application.commands.create({ + name:"reopen", + description:"Reopen this ticket.", + defaultPermission:true, + type:"CHAT_INPUT" + },sid).then(() => { + readystats++ + }) + } \ No newline at end of file diff --git a/core/ticketCloser.js b/core/ticketCloser.js index cce6df6..8a8baa4 100644 --- a/core/ticketCloser.js +++ b/core/ticketCloser.js @@ -2,7 +2,8 @@ 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 /** @@ -14,6 +15,7 @@ const storage = bot.storage exports.closeTicket = async (interaction,prefix,mode) => { const chalk = await (await import("chalk")).default const channelmessages = await interaction.channel.messages.fetch() + const channel = interaction.channel channelmessages.sweep((msgSweep) => { return msgSweep.author.id == client.user.id @@ -41,11 +43,46 @@ exports.closeTicket = async (interaction,prefix,mode) => { var enableTranscript = true 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("MANAGE_GUILD")){ + interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) + return + } + interaction.channel.delete() - if (config.logs){console.log("[system] deleted a ticket (name:"+interaction.channel.name+",user:"+interaction.user.username+")")} + log("system","deleted a ticket",[{key:"user",value:interaction.user.tag},{key:"ticket",value:interaction.channel.name}]) if (!isDatabaseError) storage.set("ticketStorage",getuserID,Number(storage.get("ticketStorage",getuserID)) - 1) + + //getID & send DM + interaction.channel.messages.fetchPinned().then(msglist => { + var firstmsg = msglist.last() + + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false + + if (!firstmsg.embeds[0].author) 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.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"){ + + 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("MANAGE_GUILD")){ + interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) + return + } + } + var permissionArray = [] if (!isDatabaseError) permissionArray.push({ id:getusernameStep1.id, @@ -69,7 +106,7 @@ exports.closeTicket = async (interaction,prefix,mode) => { .setCustomId("deleteTicket1") .setDisabled(false) .setStyle("DANGER") - .setLabel("Delete Ticket") + .setLabel(l.buttons.delete) .setEmoji("โœ–๏ธ") ) .addComponents( @@ -77,36 +114,92 @@ exports.closeTicket = async (interaction,prefix,mode) => { .setCustomId("sendTranscript") .setDisabled(false) .setStyle("SECONDARY") - .setLabel("Send Transcript File") + .setLabel(l.buttons.sendTranscript) .setEmoji("๐Ÿ“„") ) + .addComponents( + new discord.MessageButton() + .setCustomId("reopenTicket") + .setDisabled(false) + .setStyle("SUCCESS") + .setLabel(l.buttons.reopen) + .setEmoji("โœ”") + ) + const embed = new discord.MessageEmbed() .setColor(config.main_color) - .setTitle("Closed this ticket!") - .setDescription("Only admins can now talk in this ticket!\n\n*Click on the button below to delete this ticket*") + .setTitle(":lock: "+l.messages.closedTitle+" :lock:") + .setDescription(l.messages.closedDescription) interaction.channel.send({embeds:[embed],components:[closeButtonRow]}) + + log("system","closed a ticket",[{key:"user",value:interaction.user.tag},{key:"ticket",value:interaction.channel.name}]) + + //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.closedTicketDmTitle,l.messages.closedTicketDmDescription,":ticket:",config.main_color)]}) + } + } + catch{log("system","can't send DM to member, member doesn't allow dm's")} + }) + + }else if (mode == "deletenotranscript"){ + + 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("MANAGE_GUILD")){ + interaction.channel.send({embeds:[bot.errorLog.noPermsMessage]}) + return + } + enableTranscript = false interaction.channel.delete() - if (config.logs){console.log("[system] deleted a ticket (name:"+interaction.channel.name+",user:"+interaction.user.username+")")} + log("system","deleted a ticket",[{key:"user",value:interaction.user.tag},{key:"ticket",value:interaction.channel.name}]) if (!isDatabaseError) storage.set("ticketStorage",getuserID,Number(storage.get("ticketStorage",getuserID)) - 1) + + //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.deletedTicketDmTitle,l.messages.deletedTicketDmDescription,":ticket:",config.main_color)]}) + } + } + catch{log("system","can't send DM to member, member doesn't allow dm's")} + }) } if (enableTranscript == true && mode != "deletenotranscript"){ if (config.system.enable_transcript || config.system.enable_DM_transcript){ - var fileattachment = await require("./transcript").createTranscript(channelmessages) + var fileattachment = await require("./transcript").createTranscript(channelmessages,channel) - if (fileattachment == false){console.log("[transcript] internal error: no transcript is created!");return} + if (fileattachment == false){log("system","internal error: transcript is not created!");return} } if (config.system.enable_transcript){ const transcriptEmbed = new discord.MessageEmbed() .setColor(config.main_color) - .setTitle("A new transcript is here!") + .setTitle(l.messages.newTranscriptTitle) .setAuthor({name:interaction.user.username,iconURL:interaction.user.displayAvatarURL({format:"png"})}) - .setDescription("You can find the transcript in the text file above!") + .setDescription(l.messages.newTranscriptDescription) .setFooter({text:"ticket: "+ticketuserarray}) interaction.guild.channels.cache.find(c => c.id == config.system.transcript_channel).send({ @@ -118,8 +211,8 @@ exports.closeTicket = async (interaction,prefix,mode) => { if (config.system.enable_DM_transcript){ const transcriptEmbed = new discord.MessageEmbed() .setColor(config.main_color) - .setTitle("Here is a transcript of your ticket!") - .setDescription("You can find the transcript in the text file above!") + .setTitle(l.messages.newTranscriptTitle) + .setDescription(l.messages.newTranscriptDescription) .setFooter({text:"ticket: "+ticketuserarray}) if (!isDatabaseError) getusernameStep1.send({ @@ -143,14 +236,14 @@ exports.runThis = () => { return msgSweep.author.id == client.user.id }) - var fileattachment = await require("./transcript").createTranscript(channelmessages) + var fileattachment = await require("./transcript").createTranscript(channelmessages,interaction.channel) if (fileattachment == false){ - console.log("[transcript] internal error: no transcript is created!") - interaction.channel.send({content:"**Something went wrong while making the transcript!**\nPlease try again another time!"}) + log("system","internal error: transcript is not created!") + interaction.channel.send({embeds:[bot.errorLog.serverError(l.errors.somethingWentWrongTranscript)]}) return } - interaction.channel.send({content:"**Here is the transcript:**",files:[fileattachment]}) + 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 573f13c..ea9b3c3 100644 --- a/core/ticketMessageEmbed.js +++ b/core/ticketMessageEmbed.js @@ -3,6 +3,7 @@ const bot = require('../index') const client = bot.client const config = bot.config const getButton = require("./utils/getButton") +const l = bot.language /** * @@ -39,7 +40,7 @@ exports.createEmbed = (id) => { var description = data.description if (data.enableTicketExplaination){ - description = description+"\n\n__choose a category:__\n" + description = description+"\n\n__"+l.messages.chooseCategory+"__\n" var ticketExplainations = [] buttonData.forEach((button) => { @@ -51,7 +52,7 @@ exports.createEmbed = (id) => { } if (data.enableMaxTicketsWarning){ - description = description+"\n\n**Warning:** _You can only create "+config.system.max_allowed_tickets+" ticket(s) at a time!_" + description = description+"\n\n"+l.commands.maxTicketWarning.replace("{0}",config.system.max_allowed_tickets) } embed.setDescription(description) diff --git a/core/ticketOpener.js b/core/ticketOpener.js index 9cdb293..f7438a8 100644 --- a/core/ticketOpener.js +++ b/core/ticketOpener.js @@ -2,6 +2,8 @@ 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 @@ -13,7 +15,7 @@ module.exports = () => { .setCustomId("closeTicket") .setDisabled(false) .setStyle("SECONDARY") - .setLabel("Close Ticket") + .setLabel(l.buttons.close) .setEmoji("๐Ÿ”’") ) .addComponents( @@ -21,7 +23,7 @@ module.exports = () => { .setCustomId("deleteTicket") .setDisabled(false) .setStyle("DANGER") - .setLabel("Delete Ticket") + .setLabel(l.buttons.delete) .setEmoji("โœ–๏ธ") ) @@ -32,26 +34,36 @@ module.exports = () => { }else if (interaction.isButton()){ var customId = interaction.customId }else return + + if (interaction.customId.startsWith("newT")){ + const optionid = interaction.customId.split("newT")[1] + if (!optionid){ + interaction.reply({embeds:[bot.errorLog.serverError(l.errors.ticketDoesntExist)]}) + return + } + } if (getconfigoptions.getTicketValues("id").includes(customId)){ - - if (interaction.isButton()){ - interaction.deferUpdate() - }else if (interaction.isCommand()){ - interaction.reply({content:"Your ticket is created!"}) - } //ticketoptions from config const currentTicketOptions = getconfigoptions.getOptionsById(customId) + if (currentTicketOptions == false || currentTicketOptions.type != "ticket") return interaction.reply({embeds:[bot.errorLog.serverError(l.errors.anotherOption)]}) + + if (interaction.isButton()){ + interaction.deferUpdate() + }else if (interaction.isCommand()){ + interaction.reply({embeds:[bot.errorLog.success(l.messages.createdTitle,l.messages.createdDescription)]}) + } + if (storage.get("ticketStorage",interaction.member.id) == null || storage.get("ticketStorage",interaction.member.id) == "false"|| Number(storage.get("ticketStorage",interaction.member.id)) < config.system.max_allowed_tickets){ try{ if (config.system.enable_DM_Messages){ - interaction.member.send({content:currentTicketOptions.message}) + interaction.member.send({embeds:[bot.errorLog.custom(l.messages.newTicketDmTitle,currentTicketOptions.message,":ticket:",config.main_color)]}) } } - catch{console.log("[system] can't send DM to member, member doesn't allow dm's")} + catch{log("system","can't send DM to member, member doesn't allow dm's")} @@ -132,34 +144,36 @@ module.exports = () => { interaction.guild.channels.create(ticketName,{ type:"GUILD_TEXT", parent:newTicketCategory, - reason:"A new ticket was created", + reason:"A new ticket is created", permissionOverwrites:permissionsArray }).then((ticketChannel) => { storage.set("userTicketStorage",ticketChannel.id,interaction.member.id) var ticketEmbed = new discord.MessageEmbed() + .setAuthor({name:interaction.user.id}) .setColor(config.main_color) - .setTitle("You created a ticket!") - .setDescription("The staff will help you soon!\n\n*Click on the button below to close the ticket!*") + .setTitle(currentTicketOptions.name) + if (currentTicketOptions.ticketmessage.length > 0) ticketEmbed.setDescription(currentTicketOptions.ticketmessage) ticketChannel.send({ - content:"<@"+interaction.member.id+"> @everyone", + content:"<@"+interaction.member.id+"> @here", embeds:[ticketEmbed], components:[closeButton] }).then(firstmsg => { firstmsg.pin() }) - if (config.logs){console.log("[system] created a new ticket (name:"+logsname+",user:"+interaction.user.username+")")} + + log("system","created new ticket",[{key:"ticket",value:ticketName},{key:"user",value:interaction.user.tag}]) }) }else{ try { if (config.system.enable_DM_Messages){ - interaction.member.send("you already have the maximum number of tickets allowed!") + interaction.member.send({embeds:[bot.errorLog.warning(l.errors.maxAmountTitle,l.errors.maxAmountDescription)]}) } } - catch{console.log("[system] can't send DM to member, member doesn't allow dm's")} + catch{log("system","can't send DM to member, member doesn't allow dm's")} } diff --git a/core/ticketReopener.js b/core/ticketReopener.js new file mode 100644 index 0000000..af7a886 --- /dev/null +++ b/core/ticketReopener.js @@ -0,0 +1,245 @@ +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 + +module.exports = () => { + var closeRowNormal = new discord.MessageActionRow() + .addComponents( + new discord.MessageButton() + .setCustomId("closeTicket") + .setDisabled(false) + .setStyle("SECONDARY") + .setLabel(l.buttons.close) + .setEmoji("๐Ÿ”’") + ) + .addComponents( + new discord.MessageButton() + .setCustomId("deleteTicket") + .setDisabled(false) + .setStyle("DANGER") + .setLabel(l.buttons.delete) + .setEmoji("โœ–๏ธ") + ) + + var closeRowClosed = new discord.MessageActionRow() + .addComponents( + new discord.MessageButton() + .setCustomId("deleteTicket1") + .setDisabled(false) + .setStyle("DANGER") + .setLabel(l.buttons.delete) + .setEmoji("โœ–๏ธ") + ) + .addComponents( + new discord.MessageButton() + .setCustomId("sendTranscript") + .setDisabled(false) + .setStyle("SECONDARY") + .setLabel(l.buttons.sendTranscript) + .setEmoji("๐Ÿ“„") + ) + .addComponents( + new discord.MessageButton() + .setCustomId("reopenTicket") + .setDisabled(false) + .setStyle("SUCCESS") + .setLabel(l.buttons.reopen) + .setEmoji("โœ”") + ) + + var reopenBar = new discord.MessageActionRow() + .addComponents( + new discord.MessageButton() + .setCustomId("reopenTicketTrue") + .setDisabled(false) + .setStyle("SECONDARY") + .setEmoji("โœ…") + ) + .addComponents( + new discord.MessageButton() + .setCustomId("reopenTicketFalse") + .setDisabled(false) + .setStyle("SECONDARY") + .setEmoji("โŒ") + ) + + var reopenBar1 = new discord.MessageActionRow() + .addComponents( + new discord.MessageButton() + .setCustomId("reopenTicketTrue1") + .setDisabled(false) + .setStyle("SECONDARY") + .setEmoji("โœ…") + ) + .addComponents( + new discord.MessageButton() + .setCustomId("reopenTicketFalse1") + .setDisabled(false) + .setStyle("SECONDARY") + .setEmoji("โŒ") + ) + + var reopenCommandBar = new discord.MessageActionRow() + .addComponents( + new discord.MessageButton() + .setCustomId("reopenTicket1") + .setDisabled(false) + .setStyle("SECONDARY") + .setEmoji("๐Ÿ”“") + ) + + //NORMAL WAY + client.on("interactionCreate",(interaction) => { + if (!interaction.isButton()) return + if (interaction.customId != "reopenTicket") return + + interaction.deferUpdate() + interaction.message.edit({components:[reopenBar]}) + + }) + + client.on("interactionCreate",(interaction) => { + if (!interaction.isButton()) return + if (interaction.customId != "reopenTicketFalse") return + + interaction.deferUpdate() + interaction.message.edit({components:[closeRowClosed]}) + + }) + + client.on("interactionCreate",(interaction) => { + if (!interaction.isButton()) return + if (interaction.customId != "reopenTicketTrue") return + + interaction.deferUpdate() + + const embed = new discord.MessageEmbed() + .setColor(config.main_color) + .setTitle(":unlock: "+l.messages.reopenTitle+" :unlock:") + .setDescription(l.messages.reopenDescription) + + 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 = ["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"] + var everyoneDenyPerms = [] + }else{ + var everyoneAllowPerms = [] + var everyoneDenyPerms = ["VIEW_CHANNEL"] + } + permissionsArray.push({ + id:interaction.guild.id, + type:"role", + allow:everyoneAllowPerms, + deny:everyoneDenyPerms + }) + + interaction.channel.permissionOverwrites.cache.forEach((p) => { + if (p.type == "member"){ + permissionsArray.push({ + id:p.id, + type:"member", + allow:["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"], + deny:[] + }) + } + }) + + interaction.channel.permissionOverwrites.set(permissionsArray) + }) + + + //COMMAND WAY + client.on("interactionCreate",(interaction) => { + if (!interaction.isButton()) return + if (interaction.customId != "reopenTicket1") return + + interaction.deferUpdate() + interaction.message.edit({components:[reopenBar1]}) + + }) + + client.on("interactionCreate",(interaction) => { + if (!interaction.isButton()) return + if (interaction.customId != "reopenTicketFalse1") return + + interaction.deferUpdate() + interaction.message.edit({components:[reopenCommandBar]}) + + }) + + client.on("interactionCreate",(interaction) => { + if (!interaction.isButton()) return + if (interaction.customId != "reopenTicketTrue1") return + + interaction.deferUpdate() + + const embed = new discord.MessageEmbed() + .setColor(config.main_color) + .setTitle(":unlock: "+l.messages.reopenTitle+" :unlock:") + .setDescription(l.messages.reopenDescription) + + 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 = ["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"] + var everyoneDenyPerms = [] + }else{ + var everyoneAllowPerms = [] + var everyoneDenyPerms = ["VIEW_CHANNEL"] + } + permissionsArray.push({ + id:interaction.guild.id, + type:"role", + allow:everyoneAllowPerms, + deny:everyoneDenyPerms + }) + + interaction.channel.permissionOverwrites.cache.forEach((p) => { + if (p.type == "member"){ + permissionsArray.push({ + id:p.id, + type:"member", + allow:["ADD_REACTIONS","ATTACH_FILES","EMBED_LINKS","SEND_MESSAGES","VIEW_CHANNEL"], + 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")} + }) + }) +} \ No newline at end of file diff --git a/core/transcript.js b/core/transcript.js index 61a0dd0..e1a9308 100644 --- a/core/transcript.js +++ b/core/transcript.js @@ -2,20 +2,56 @@ const discord = require('discord.js') const bot = require('../index') const client = bot.client const config = bot.config +const l = bot.language + +/** @param {discord.TextBasedChannel} channel @returns {Promise<{ticketname:String,ticketopener:{discordjsuser:discord.User,name:String,id:String}>} */ +const getUserInfo = (channel) => { + return new Promise((promiseresolve,reject) => { + //getID + var result = { + ticketopener:{ + discordjsuser:"", + id:"/", + name:"/" + }, + ticketname:"/" + } + 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 ? firstmsg.embeds[0].author.name : false + + result.ticketopener.id = id + + const ticketopener = client.users.cache.find(u => u.id == id) + const name = ticketopener.tag + + const channelname = channel.name + + promiseresolve({ticketname:channelname,ticketopener:{discordjsuser:ticketopener,name:name,id:id}}) + }) + }) +} /** * * @param {discord.Message[]} messagecollection + * @param {discord.Channel} channel * @returns new `discord.messageAttachment` */ -exports.createTranscript = async (messagecollection) => { +exports.createTranscript = async (messagecollection,channel) => { + const ticketuserdata = await getUserInfo(channel) try { - const filearray = ["TRANSCRIPT START:"] + const cd = new Date() + const months = ["January","February","March","April","May","June","July","August","September","October","November","December"] + const dateString = cd.getDate()+" "+months[cd.getMonth()-1]+" "+cd.getFullYear()+" - "+cd.getSeconds()+":"+cd.getMinutes()+":"+cd.getHours() + const filearray = ["open ticket transcript:\ntranscript creation: "+dateString+"\nticket name: "+ticketuserdata.ticketname+"\nticket opener: "+ticketuserdata.ticketopener.name,"\nTRANSCRIPT START:"] messagecollection.reverse() - messagecollection.forEach((msg) => { const timestamp = new Date(msg.createdTimestamp) @@ -28,9 +64,9 @@ exports.createTranscript = async (messagecollection) => { if (filearray.length < 2) filearray.push("transcript is empty") const filestring = filearray.join("\n") const filebuff = Buffer.from(filestring,"utf-8") - return new discord.MessageAttachment(filebuff,"transcript.txt") + return new discord.MessageAttachment(filebuff,"transcript_"+ticketuserdata.ticketname+".txt") }catch(err){ - console.log(err) + console.log("[error] "+err) return false } } \ No newline at end of file diff --git a/core/utils/getButton.js b/core/utils/getButton.js index e49a9da..2223414 100644 --- a/core/utils/getButton.js +++ b/core/utils/getButton.js @@ -2,6 +2,7 @@ const discord = require("discord.js") const bot = require("../../index") const config = bot.config const getoptions = require("../getoptions") +const l = bot.language /**@returns {"DANGER"|"SUCCESS"|"PRIMARY"|"SECONDARY"} */ const getColor = (color) => { @@ -87,6 +88,7 @@ exports.rawButtonData = class { this.channelprefix = "" this.category = "" this.message = "" + this.ticketmessage = "" } } \ No newline at end of file diff --git a/core/utils/getTicketMessages.js b/core/utils/getTicketMessages.js index 22ed608..bd97d14 100644 --- a/core/utils/getTicketMessages.js +++ b/core/utils/getTicketMessages.js @@ -1,5 +1,7 @@ const bot = require("../../index") const config = bot.config +const l = bot.language + exports.getTicketMessage = (input) => { var returned = config.messages.find(a => a.id == input) if (returned){ diff --git a/index.js b/index.js index 193d7b6..a5cdde5 100644 --- a/index.js +++ b/index.js @@ -1,14 +1,33 @@ +// __________ __________ ___________ ____ ____ +// / ____ \ / ______ \ / | | \ | | +// | / \ | | | | | | |_______| | \ | | +// | | | | | |____| | | | | |\ \ | | +// | | | | | ________/ | |______ | | \ \ | | +// | | | | | | | _____| | | \ \ | | +// | | | | | | | | | | \ \ | | +// | | | | | | | |________ | | \ \| | +// | \____/ | | | | | | | \ | +// \__________/ |__| \__________| |__| \___| + + const discord = require('discord.js') const fs = require('fs') const intents = discord.Intents const client = new discord.Client({intents:[intents.FLAGS.GUILDS,intents.FLAGS.GUILD_MESSAGES,intents.FLAGS.GUILD_MEMBERS],partials:["CHANNEL"]}) exports.client = client -client.setMaxListeners(20) +client.setMaxListeners(30) -//change to FALSE on release -const isDev = false -//!!!!!!!!!!! +if (process.argv[2]){ + if (process.argv[2].endsWith("d")){ + var isDev = true + console.log("starting in dev mode...") + }else{var isDev = false} +}else{var isDev = false} + +exports.developerMode = isDev +const language = require("./core/languageManager").language +exports.language = language if (isDev){ try { @@ -19,15 +38,24 @@ if (isDev){ } }else{var config = require('./config.json')} exports.config = config +exports.errorLog = require("./core/errorLogSystem") +const log = this.errorLog.log client.on('ready',async () => { const chalk = await (await import("chalk")).default - if (process.argv[2] != "slash"){ - console.log(chalk.green("open-ticket ready!")) - if (config.logs){console.log(chalk.white("\n\nlogs:\n============"))} + + if (!process.argv[2].startsWith("slash")){ + console.log(chalk.red("WELCOME TO OPEN TICKET!")) + log("info","open ticket ready",[{key:"version",value:require("./package.json").version},{key:"language",value:config.languagefile}]) + + console.log(chalk.blue("\n\nlogs:")+"\n============") if (config.status.enabled){ client.user.setActivity(config.status.text,{type:config.status.type}) } + + log("system","bot logged in!") + + await client.guilds.cache.find((g) => g.id == config.server_id).members.fetch() }else{ console.log(chalk.red("STARTING IN ")+chalk.blue("SLASH MODE")+chalk.red("...")) console.log("logs:\n================") @@ -46,9 +74,11 @@ client.on('ready',async () => { } }) -require("./core/checker").checker() +if (!isDev){ + require("./core/checker").checker() +} -if (process.argv[2] != "slash"){ +if (process.argv[2] && !process.argv[2].startsWith("slash")){ var storage = require('./core/dynamicdatabase/storage') exports.storage = storage @@ -60,66 +90,38 @@ if (process.argv[2] != "slash"){ require("./commands/rename")() require("./commands/add")() require("./commands/remove")() + require("./commands/reopen")() //core require('./core/ticketOpener')() require("./core/ticketCloser").runThis() require("./core/closebuttons")() require("./core/reactionRoles")() - - /** - * We need: - * - checker.js - */ + require("./core/ticketReopener")() } - -//===================================================================== -//===================================================================== -//ERROR DEBUG MODE: turn not on exept when you know what you are doing! -var errorDebugMode = false -//ERROR DEBUG MODE: turn not on exept when you know what you are doing! -//===================================================================== -//===================================================================== - - - -if (!errorDebugMode){ - 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")) - }) +const debugLog = (debugString) => { + const content = fs.existsSync("./openticketdebug.txt") ? fs.readFileSync("./openticketdebug.txt").toString() : "==========================\n\n==========================" + fs.writeFileSync("./openticketdebug.txt",content+"\nDEBUG: "+debugString) } -if (errorDebugMode) { - const debugLog = (debugString) => { - const content = fs.existsSync("./openticketdebug.txt") ? fs.readFileSync("./openticketdebug.txt").toString() : "==========================\n\n==========================" - fs.writeFileSync("./openticketdebug.txt",content+"\nDEBUG: "+debugString) - } - const errorLog = (errorString,stack) => { - const content = fs.existsSync("./openticketdebug.txt") ? fs.readFileSync("./openticketdebug.txt").toString() : "==========================\n\n==========================" - fs.writeFileSync("./openticketdebug.txt",content+"\nERROR: "+errorString+" STACK: "+stack) - } - - client.on("debug", async (message) => { - if (message.startsWith("Provided token:")){ - debugLog("Provided token: ***********bot token is invisible**************...") - return - } - debugLog(message) - }); - - const asyncfunction = async () => { - const chalk = await (await import("chalk")).default - console.log("\n\nopen-ticket debug:\n"+chalk.bgYellow("ENTERING DEBUG MODE:")) - } - asyncfunction() - - process.on("uncaughtException",async (error,origin) => { - const chalk = await (await import("chalk")).default - console.log(chalk.red("\nMAIN ERROR: ")+"this error is saved in the debug file!") - errorLog(error.name+": "+error.message+" | origin: "+origin,error.stack) - }) +const errorLog = (errorString,stack) => { + const content = fs.existsSync("./openticketdebug.txt") ? fs.readFileSync("./openticketdebug.txt").toString() : "==========================\n\n==========================" + fs.writeFileSync("./openticketdebug.txt",content+"\nERROR: "+errorString+" STACK: "+stack) } +client.on("debug", async (message) => { + if (message.startsWith("Provided token:")){ + debugLog("Provided token: ***********bot token is invisible**************...") + return + } + debugLog(message) +}); + +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) +}) + client.login(config.auth_token) \ No newline at end of file diff --git a/language/custom.json b/language/custom.json new file mode 100644 index 0000000..2816d86 --- /dev/null +++ b/language/custom.json @@ -0,0 +1,77 @@ +{ + "errors":{ + "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!", + "chooseFromListTitle":"Invalid ID", + "chooseFromListDescription":"Choose one of the id's below:", + "boterror":"Bot Error!", + "notInTicketTitle":"You are not in a ticket!", + "notInTicketDescription":"This command doesn't work outside tickets!", + "ticketDoesntExist":"This ticket doesn't exist anymore!", + "roleDoesntExist":"This role doesn't exist anymore!", + "anotherOption":"This option is not a ticket but another type!", + "maxAmountTitle":"Max amount reached!", + "maxAmountDescription":"You reached the maximum number of tickets allowed!\nSo you can't create a new one!", + "somethingWentWrong":"Something went wrong!**\nPlease try again another time!", + "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!", + + "ticketWarning":"The embed is in the message below!", + "maxTicketWarning":"**Warning:** _You can only create {0} ticket(s) at a time!_" + }, + "helpMenu":{ + "title":"Help Menu:", + "header1":"**Go to {0} to create a ticket!**\n\n", + "header2":"**Run the command `/new` or `/ticket` to create a ticket!**\n\n", + + "msgCmd":"Spawn an embed with buttons. (admins only)", + "renameCmd":"Rename a ticket. (no spaces)", + "closeCmd":"Close a ticket.", + "deleteCmd":"Delete a ticket.", + "addCmd":"Add a user to the ticket.", + "removeCmd":"Remove a user from the ticket.", + "reopenCmd":"Re-Open a ticket after it was closed." + }, + "buttons":{ + "close":"Close Ticket", + "delete":"Delete Ticket", + "reopen":"Re-Open Ticket", + "sendTranscript":"Send Transcript File" + }, + "messages":{ + "reopenTitle":"Re-Opened this ticket!", + "reopenDescription":"Feel free to talk again!", + "closedTitle":"Closed this ticket!", + "closedDescription":"Only admins can talk in this ticket now!\n\n*Click on the button below to delete or to re-open this ticket!*", + "createdTitle":"Ticket Created!", + "createdDescription":"Your ticket is created, you can detect it by a ping!", + + "newTicketDmTitle":"New Ticket!", + "closedTicketDmTitle":"Ticket Closed!", + "deletedTicketDmTitle":"Ticket Deleted!", + "closedTicketDmDescription":"Your ticket is closed!", + "deletedTicketDmDescription":"Your ticket is deleted!", + "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:" + } +} \ No newline at end of file diff --git a/language/dutch.json b/language/dutch.json new file mode 100644 index 0000000..2604cc5 --- /dev/null +++ b/language/dutch.json @@ -0,0 +1,79 @@ +{ + "errors":{ + "missingArgsTitle":"Ongeldige Argumenten!", + "missingArgsDescription":"Geen Argument", + "noPermsTitle":"Geen permissies!", + "noPermsDescription":"Je hebt niet de juiste rollen om deze command uit te voeren!\nJe hebt de `ADMINISTRATOR` permissie nodig of je moet in de lijst van toegestane rollen zitten!", + "chooseFromListTitle":"Ongeldig ID", + "chooseFromListDescription":"Kies een van deze id's:", + "boterror":"Bot Error!", + "notInTicketTitle":"Je bent niet in een ticket!", + "notInTicketDescription":"Deze command werkt niet buiten tickets!", + "ticketDoesntExist":"Dit ticket bestaat niet meer!", + "roleDoesntExist":"Deze rol bestaat niet meer!", + "anotherOption":"Deze optie is geen ticket maar een ander type!", + "maxAmountTitle":"Max aantal bereikt!", + "maxAmountDescription":"Je hebt het maximum aantal openstaande ticket bereikt!\nDus je kan er geen nieuwe maken!", + "somethingWentWrong":"Iets ging fout!**\nProbeer een andere keer opnieuw!", + "somethingWentWrongTranscript":"Iets ging fout bij het maken van het transcript!**\nProbeer een andere keer opnieuw!" + }, + "commands":{ + "userAddedTitle":"User Toegevoegd!", + "userAddedDescription":"{0} is toegevoegd aan dit ticket!", + "userRemovedTitle":"User Verwijderd!", + "userRemovedDescription":"{0} is verwijderd van dit ticket!", + + "renameTitle":"De naam is veranderd!", + "renameWarning":"Waarschuwing: je kan de kanaalnaam maar 2 keer per minuut veranderen!\n(dit heeft te maken met discord rate limits)", + + "closeTitle":"Sluit dit ticket!", + "closeDescription":"Je kan dit ticket sluiten door op de knop hier onder te duwen!", + "deleteTitle":"Verwijder dit ticket!", + "deleteDescription":"Je kan dit ticket verwijderen door op de knop hier onder te duwen!", + "reopenTitle":"Heropen dit ticket!", + "reopenDescription":"Je kan dit ticket heropenen door op de knop hier onder te duwen!", + + "ticketWarning":"De embed is in het bericht hier onder!", + "maxTicketWarning":"**Waarschuwing:** _Je kan maar {0} ticket(s) tegelijkertijd aanmaken!_" + }, + "helpMenu":{ + "title":"Help Menu:", + "header1":"**Ga naar {0} om een ticket te maken!**\n\n", + "header2":"**Run de command `/new` of `/ticket` om een ticket te maken!**\n\n", + + "msgCmd":"Spawn een embed met knoppen. (admins only)", + "renameCmd":"Hernoem een ticket. (geen spaties)", + "closeCmd":"Sluit een ticket.", + "deleteCmd":"Verwijder een ticket.", + "addCmd":"Voeg een user toe aan een ticket.", + "removeCmd":"Verwijder een user van een ticket.", + "reopenCmd":"Heropen een ticket nadat het gesloten wordt." + }, + "buttons":{ + "close":"Sluit Ticket", + "delete":"Verwijder Ticket", + "reopen":"Heropen Ticket", + "sendTranscript":"Stuur Transcript Bestand" + }, + "messages":{ + "reopenTitle":"Dit ticket is terug geopend!", + "reopenDescription":"Voel vrij om terug te praten!", + "closedTitle":"Dit ticket is gesloten!", + "closedDescription":"Nu kunnen alleen nog admins praten in dit ticket!\n\n*Klik op de knop hier onder om het ticket terug te openen of te verwijderen!*", + "createdTitle":"Ticket Gemaakt!", + "createdDescription":"Je ticket is gemaakt, je kan het detecteren bij een ping!", + + "newTicketDmTitle":"Nieuw Ticket!", + "closedTicketDmTitle":"Ticket Gesloten!", + "deletedTicketDmTitle":"Ticket Verwijderd!", + "closedTicketDmDescription":"Je ticket is gesloten!", + "deletedTicketDmDescription":"Je ticket is verwijderd!", + "reopenTicketDmTitle":"Ticket Heropend!", + "reopenTicketDmDescription":"Je ticket is heropend!", + "newTranscriptTitle":"Een nieuw transcript is hier!", + "newTranscriptDescription":"Je kan het transcript vinden in het bestand hierboven!", + "hereIsTheTranscript":"Hier is het transcript:", + + "chooseCategory":"kies een categorie:" + } +} \ No newline at end of file diff --git a/language/english.json b/language/english.json new file mode 100644 index 0000000..7c36997 --- /dev/null +++ b/language/english.json @@ -0,0 +1,79 @@ +{ + "errors":{ + "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!", + "chooseFromListTitle":"Invalid ID", + "chooseFromListDescription":"Choose one of the id's below:", + "boterror":"Bot Error!", + "notInTicketTitle":"You are not in a ticket!", + "notInTicketDescription":"This command doesn't work outside tickets!", + "ticketDoesntExist":"This ticket doesn't exist anymore!", + "roleDoesntExist":"This role doesn't exist anymore!", + "anotherOption":"This option is not a ticket but another type!", + "maxAmountTitle":"Max amount reached!", + "maxAmountDescription":"You reached the maximum number of tickets allowed!\nSo you can't create a new one!", + "somethingWentWrong":"Something went wrong!**\nPlease try again another time!", + "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!", + + "ticketWarning":"The embed is in the message below!", + "maxTicketWarning":"**Warning:** _You can only create {0} ticket(s) at a time!_" + }, + "helpMenu":{ + "title":"Help Menu:", + "header1":"**Go to {0} to create a ticket!**\n\n", + "header2":"**Run the command `/new` or `/ticket` to create a ticket!**\n\n", + + "msgCmd":"Spawn an embed with buttons. (admins only)", + "renameCmd":"Rename a ticket. (no spaces)", + "closeCmd":"Close a ticket.", + "deleteCmd":"Delete a ticket.", + "addCmd":"Add a user to the ticket.", + "removeCmd":"Remove a user from the ticket.", + "reopenCmd":"Re-Open a ticket after it was closed." + }, + "buttons":{ + "close":"Close Ticket", + "delete":"Delete Ticket", + "reopen":"Re-Open Ticket", + "sendTranscript":"Send Transcript File" + }, + "messages":{ + "reopenTitle":"Re-Opened this ticket!", + "reopenDescription":"Feel free to talk again!", + "closedTitle":"Closed this ticket!", + "closedDescription":"Only admins can talk in this ticket now!\n\n*Click on the button below to delete or to re-open this ticket!*", + "createdTitle":"Ticket Created!", + "createdDescription":"Your ticket is created, you can detect it by a ping!", + + "newTicketDmTitle":"New Ticket!", + "closedTicketDmTitle":"Ticket Closed!", + "deletedTicketDmTitle":"Ticket Deleted!", + "closedTicketDmDescription":"Your ticket is closed!", + "deletedTicketDmDescription":"Your ticket is deleted!", + "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:" + } +} \ No newline at end of file diff --git a/language/romanian.json b/language/romanian.json new file mode 100644 index 0000000..a33d6a5 --- /dev/null +++ b/language/romanian.json @@ -0,0 +1,79 @@ +{ + "errors":{ + "missingArgsTitle":"Argumente invalide!", + "missingArgsDescription":"Argument lipsa", + "noPermsTitle":"Nu ai permisiunile necesare!", + "noPermsDescription":"Nu ai rolurile necesare!\nAi nevoie de permisiunea `ADMINISTRATOR` sau sa fii in lista rolurilor permise!", + "chooseFromListTitle":"ID invalid", + "chooseFromListDescription":"Alege unul dintre id-urile urmatoare:", + "boterror":"Eroare bot!", + "notInTicketTitle":"Nu esti intr-un ticket!", + "notInTicketDescription":"Aceasta comanda nu functioneaza in afara ticket-urilor!", + "ticketDoesntExist":"Acest ticket nu mai exista!", + "roleDoesntExist":"Acest rol nu mai exista", + "anotherOption":"Aceasta optiune nu este un ticket ci doar alt tip!", + "maxAmountTitle":"Limita a fost atinsa", + "maxAmountDescription":"Ai atins limita maxima de tickete\nNu mai poti creea altele!", + "somethingWentWrong":"**Ceva nu a mers bine :(**\nTe rugam sa incerci din nou mai tarziu", + "somethingWentWrongTranscript":"**Ceva nu a mers bine in timpul creerii copiei a ticket-ului!**\nTe rugam sa incerci din nou mai tarziu!" + }, + "commands":{ + "userAddedTitle":"Utilizator adaugat!", + "userAddedDescription":"{0} este adaugat la acest ticket!", + "userRemovedTitle":"Utilizator eliminat!", + "userRemovedDescription":"{0} este eliminat din acest ticket!", + + "renameTitle":"Numele este schimbat!", + "renameWarning":"ATENTIE: poti schimba numele acestui ticket doar de 2 ori pe minut!\n(se datoreaza limitarii discord-ului)", + + "closeTitle":"Inchide acest ticket", + "closeDescription":"Poti inchide acest ticket doar apasand butonul de mai jos!", + "deleteTitle":"Sterge acest ticket!", + "deleteDescription":"Poti sterge acest ticket doar apasand butonul de mai jos", + "reopenTitle":"Re-deschide acest ticket!", + "reopenDescription":"Poti redeschide acest ticket doar apasand butonul de mai jos!", + + "ticketWarning":"Embed-ul se afla in mesajul de mai jos:", + "maxTicketWarning":"**ATENTIE:** _Poti creea doar {0} ticket-e odata!_" + }, + "helpMenu":{ + "title":"Meniu de ajutor:", + "header1":"**Deschide {0} pentru a creea un ticket!**\n\n", + "header2":"**Ruleaza comanda `/new` ori `/ticket` pentru a creea un ticket!**\n\n", + + "msgCmd":"Afiseaza embed-ul cu tickete. (doar administratorii)", + "renameCmd":"Redenumeste un ticket. (fara spatii)", + "closeCmd":"Redenumeste un ticket ticket.", + "deleteCmd":"Sterge un ticket a ticket.", + "addCmd":"adauga un utilizator la ticket.", + "removeCmd":"Elimina un utilizator de la ticket.", + "reopenCmd":"Re-deschide un ticket dupa ce a fost inchis." + }, + "buttons":{ + "close":"Inchide Ticket-ul", + "delete":"Sterge Ticket-ul", + "reopen":"Re-deschide Ticket-ul", + "sendTranscript":"Trimite copia chat-ului ticket-ului" + }, + "messages":{ + "reopenTitle":"Ticket re-deschis", + "reopenDescription":"Simte-te comfortabil sa vorbesti din nou!", + "closedTitle":"Inchide acest ticket ticket!", + "closedDescription":"Doar administratorii pot vorbi in acest ticket de acum!\n\n*Apasa pe butonele de mai jos pentru a inchide/deschide ticket-ul!*", + "createdTitle":"Ticket Creat!", + "createdDescription":"Ticket-ul tau a fost creat, il poti vedea dupa mentionarea ta!", + + "newTicketDmTitle":"Ticket Nou!", + "closedTicketDmTitle":"Ticket รฎnchis!", + "deletedTicketDmTitle":"Ticket ศ™ters!", + "closedTicketDmDescription":"Ticket-ul tau este รฎnchis!", + "deletedTicketDmDescription":"Ticket-ul tau este ศ™ters!", + "reopenTicketDmTitle":"Ticket Re-deschis!", + "reopenTicketDmDescription":"Ticket-ul tau este re-deschis!", + "newTranscriptTitle":"O noua copie a ticket-ului este aici!", + "newTranscriptDescription":"Poti vedea copia ticket-ului in fisierul .txt de mai sus!", + "hereIsTheTranscript":"Aceasta este copia ticket-ului:", + + "chooseCategory":"Alege o categorie:" + } +} \ No newline at end of file diff --git a/openmod.png b/openmod.png new file mode 100644 index 0000000..9217e72 Binary files /dev/null and b/openmod.png differ diff --git a/package.json b/package.json index 21b6826..ed064d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-ticket", - "version": "2.0.0", + "version": "2.1.0", "description": "This is an open-source discord ticket bot, you can configure it and it comes with cool features like a transcript.", "main": "index.js", "scripts": { @@ -14,7 +14,7 @@ "license": "ISC", "dependencies": { "chalk": "^5.0.1", - "discord.js": "^13.6.0", + "discord.js": "^13.8.0", "express": "^4.17.1", "node": "^16.10.0", "node-localstorage": "^2.2.1" diff --git a/storage/.DS_Store b/storage/.DS_Store index 0d1cdd1..8fa4022 100644 Binary files a/storage/.DS_Store and b/storage/.DS_Store differ