diff --git a/.gitignore b/.gitignore index f7290d8..2c3ca30 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,9 @@ developerChangelog.md storage/dynamicDB/ storage/slashcmdEnabled.txt storage/database.json +storage/tsdatabase.json storage/.DS_Store .vscode/ livestatus.json -test.js \ No newline at end of file +test.js +testtsconfig.json \ No newline at end of file diff --git a/README.md b/README.md index a1a838b..95774fb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Open Ticket -[![discord](https://img.shields.io/badge/discord-join%20our%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) [![version](https://img.shields.io/badge/version-3.1.0-brightgreen.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/releases/tag/v3.1.0) [![discord.js](https://img.shields.io/badge/discord.js-v14-CB3837.svg?style=flat-square&logo=npm)]() [![license](https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/blob/main/LICENSE) [![documentation](https://img.shields.io/badge/documentation-Click%20Here-yellow.svg?style=flat-square)](https://docs.openticket.dj-dj.be) +[![discord](https://img.shields.io/badge/discord-join%20our%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) [![version](https://img.shields.io/badge/version-3.2.0-brightgreen.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/releases/tag/v3.2.0) [![discord.js](https://img.shields.io/badge/discord.js-v14-CB3837.svg?style=flat-square&logo=npm)]() [![license](https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square)](https://github.com/DJj123dj/open-ticket/blob/main/LICENSE) [![documentation](https://img.shields.io/badge/documentation-Click%20Here-yellow.svg?style=flat-square)](https://docs.openticket.dj-dj.be) Open ticket is the most configurable open-source ticket bot for discord! Made with the newest technologies. Like: Slash commands, transcripts, multiple ticket types, buttons & dropdowns! Start using it now, you can do anything! @@ -15,16 +15,18 @@ Start using it now, you can do anything! - Sanke: for translation & new ideas - Everyone that reported a bug #### And our translators! -- ExothDE -- 1x1 -- Redactado -- t0miiis -- josuens14 -- M4 -- David. -- Maurizio +- Sanke#6086 (Romanian & French) +- Redactado#1673 (Spanish) +- t0miiis#3022 (Czech) +- josuens14 (Spanish) +- M4#5882 (Arabic) +- ChilledBroke#9986 (Arabic) +- David.#0187 (German) +- Maurizio#0268 (Italian) +- the_gamer#5095 (Danish) ## features +- **🎉 NEW! html transcripts!** - discord interaction buttons - slash & text commands - close, delete & re-open tickets @@ -39,9 +41,6 @@ Start using it now, you can do anything! - custom API + plugins - unlimited tickets spread over multiple messages - close with reason - -*comming soon* -- share transcripts - view transcripts in html ## quick start @@ -52,7 +51,7 @@ Start using it now, you can do anything! ## information -_v3.1.0_ +_v3.2.0_ changelog: [click here](https://docs.openticket.dj-dj.be/other/changelog) diff --git a/commands/change.js b/commands/change.js new file mode 100644 index 0000000..052e2fa --- /dev/null +++ b/commands/change.js @@ -0,0 +1,101 @@ +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 permsChecker = require("../core/utils/permisssionChecker") + +const APIEvents = require("../core/api/modules/events") +const DISABLE = require("../core/api/api.json").disable + +module.exports = () => { + bot.errorLog.log("debug","COMMANDS: loaded change.js") + + if (!DISABLE.commands.text.change) client.on("messageCreate",msg => { + if (!msg.content.startsWith(config.prefix+"change")) return + + if (!msg.guild) return + if (!permsChecker.command(msg.author.id,msg.guild.id)){ + permsChecker.sendUserNoPerms(msg.author) + return + } + + msg.channel.messages.fetchPinned().then(msglist => { + var firstmsg = msglist.last() + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return msg.channel.send({embeds:[bot.errorLog.notInATicket]}) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type").value + + var newtype = msg.content.split(config.prefix+"change")[1].substring(1) + if (!newtype) return msg.channel.send({embeds:[bot.errorLog.invalidArgsMessage(l.errors.missingArgsDescription+" ``:\n`"+config.prefix+"change `")]}) + + const newTicket = require("../core/utils/configParser").getTicketById(newtype) + const list = [] + config.options.forEach((o) => list.push(o.id)) + if (!newTicket) return bot.errorLog.invalidIdChooseFromList(list) + + /**@type {String} */ + var chName = msg.channel.name + const splitted = chName.split("-") + const prefix = splitted.shift() + const name = (splitted.length > 0) ? splitted.join("-") : prefix + + + msg.channel.setName(newTicket.channelprefix+name) + msg.channel.send({embeds:[bot.embeds.commands.changeEmbed(msg.author,newtype)]}) + + log("command","someone used the 'change' command",[{key:"user",value:msg.author.tag}]) + log("system","ticket type changed",[{key:"user",value:msg.author.tag},{key:"ticket",value:name},{key:"newtype",value:newtype}]) + APIEvents.onCommand("change",permsChecker.command(msg.author.id,msg.guild.id),msg.author,msg.channel,msg.guild,new Date()) + }) + + + }) + + if (!DISABLE.commands.slash.change) client.on("interactionCreate",(interaction) => { + if (!interaction.isChatInputCommand()) return + if (interaction.commandName != "change") return + + if (!interaction.guild) return + if (!permsChecker.command(interaction.user.id,interaction.guild.id)){ + permsChecker.sendUserNoPerms(interaction.user) + return + } + + //interaction.deferReply() + interaction.channel.messages.fetchPinned().then(msglist => { + var firstmsg = msglist.last() + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return interaction.reply({embeds:[bot.errorLog.notInATicket]}) + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type").value + + console.log("HELLO WORLD!! 1") + var newtype = interaction.options.getString("type",true) + if (!newtype) return interaction.reply({embeds:[bot.errorLog.invalidArgsMessage(l.errors.missingArgsDescription+" ``:\n`"+config.prefix+"change `")]}) + + console.log("HELLO WORLD!! 2") + const newTicket = require("../core/utils/configParser").getTicketById(newtype,true) + const list = [] + config.options.forEach((o) => list.push(o.id)) + if (!newTicket) return bot.errorLog.invalidIdChooseFromList(list) + + console.log("HELLO WORLD!! 3") + /**@type {String} */ + var chName = interaction.channel.name + const splitted = chName.split("-") + const prefix = splitted.shift() + const name = (splitted.length > 0) ? splitted.join("-") : prefix + + console.log("HELLO WORLD!! 4") + + interaction.channel.setName(newTicket.channelprefix+name) + interaction.reply({embeds:[bot.embeds.commands.changeEmbed(interaction.user,newtype)]}) + + console.log("HELLO WORLD!! 5") + log("command","someone used the 'change' command",[{key:"user",value:interaction.user.tag}]) + log("system","ticket type changed",[{key:"user",value:interaction.user.tag},{key:"ticket",value:name},{key:"newtype",value:newtype}]) + APIEvents.onCommand("change",permsChecker.command(interaction.user.id,interaction.guild.id),interaction.user,interaction.channel,interaction.guild,new Date()) + }) + }) +} \ No newline at end of file diff --git a/commands/help.js b/commands/help.js index 9c19abc..03b6215 100644 --- a/commands/help.js +++ b/commands/help.js @@ -21,8 +21,6 @@ module.exports = () => { const header = config.system.ticket_channel ? l.helpMenu.header1.replace("{0}","<#"+config.system.ticket_channel+">") : l.helpMenu.header2 helpEmbed.setDescription(header+"`"+prefix+msgName+" ` ➜ _"+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",iconURL:"https://raw.githubusercontent.com/DJj123dj/open-ticket/main/logo.png"}) - var otherprefix = prefix.endsWith(" ") ? prefix.substring(0,prefix.length-1) : prefix if (!DISABLE.commands.text.help) client.on("messageCreate",msg => { diff --git a/config.json b/config.json index cab7717..6b87d5e 100644 --- a/config.json +++ b/config.json @@ -6,7 +6,6 @@ "prefix":"!ticket ", "languagefile":"english", - "credits":true, "status":{ "enabled":true, "type":"PLAYING", @@ -22,9 +21,7 @@ "member_role":"member role (doesn't have access to tickets)", "closeMode":"adminonly|normal", - "enable_transcript":false, - "enable_DM_transcript":false, - "transcript_channel":"channel id", + "transcripts":"!!!! ALL SETTINGS FOR TRANSCRIPTS ARE LOCATED IN: transcriptconfig.json !!!!", "showSlashcmdsInHelp":false }, @@ -92,7 +89,7 @@ "dropdown":false, "enableFooter":false, - "footer":"Open Ticket v3.1.0 - I'm a footer!", + "footer":"Open Ticket v3.2.0 - I'm a footer!", "enableThumbnail":false, "thumbnail":"https://www.example.com/catmemes/cat.png", diff --git a/core/api/api.json b/core/api/api.json index 6832775..d82b261 100644 --- a/core/api/api.json +++ b/core/api/api.json @@ -29,7 +29,8 @@ "remove":false, "rename":false, "claim":false, - "unclaim":false + "unclaim":false, + "change":false }, "slash":{ "help":false, @@ -42,7 +43,8 @@ "remove":false, "rename":false, "claim":false, - "unclaim":false + "unclaim":false, + "change":false } }, "checkerjs":{ diff --git a/core/api/modules/events.js b/core/api/modules/events.js index 5536ffb..f51f503 100644 --- a/core/api/modules/events.js +++ b/core/api/modules/events.js @@ -17,6 +17,10 @@ const ticketReopenListeners = [] const ticketAddListeners = [] const ticketRemoveListeners = [] +const ticketClaimListeners = [] +const ticketUnclaimListeners = [] +const ticketChangeListeners = [] + const transcriptCreationListeners = [] const commandListeners = [] @@ -146,6 +150,66 @@ exports.onTicketRemove = (user,editeduser,channel,guild,date,ticketdata) => { } +/** + * + * @param {discord.User} user + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:configParser.OTTicketOptions}} ticketdata + */ +exports.onTicketClaim = (user,channel,guild,date,ticketdata) => { + //system + bot.errorLog.log("api","user claimed a ticket",[{key:"userid",value:user.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)}]) + + ticketClaimListeners.forEach((func) => { + try { + func(user,channel,guild,date,ticketdata) + }catch{} + }) + +} + +/** + * + * @param {discord.User} user + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:configParser.OTTicketOptions}} ticketdata + */ +exports.onTicketUnclaim = (user,channel,guild,date,ticketdata) => { + //system + bot.errorLog.log("api","user unclaimed a ticket",[{key:"userid",value:user.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)}]) + + ticketUnclaimListeners.forEach((func) => { + try { + func(user,channel,guild,date,ticketdata) + }catch{} + }) + +} + +/** + * @param {String} newtype + * @param {discord.User} user + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:configParser.OTTicketOptions}} ticketdata + */ +exports.onTicketChange = (newtype,user,channel,guild,date,ticketdata) => { + //system + bot.errorLog.log("api","user changed ticket type",[{key:"newtype",value:newtype},{key:"userid",value:user.id},{key:"channelid",value:channel.id},{key:"guildid",value:guild.id},{key:"ticketdata",value:JSON.stringify(ticketdata)}]) + + ticketChangeListeners.forEach((func) => { + try { + func(newtype,user,channel,guild,date,ticketdata) + }catch{} + }) + +} + /** * * @param {discord.Message[]} messages @@ -165,7 +229,7 @@ exports.onTranscriptCreation = (messages,channel,guild,date) => { } -/**@typedef {"help"|"message"|"close"|"delete"|"reopen"|"rename"|"add"|"remove"} OTCommandType */ +/**@typedef {"help"|"message"|"close"|"delete"|"reopen"|"rename"|"add"|"remove"|"claim"|"unclaim"|"change"} OTCommandType */ /** * @@ -269,6 +333,16 @@ exports.onCommand = (type,hasPerms,user,channel,guild,date) => { * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:configParser.OTTicketOptions}} ticketdata */ +/** + * @callback TicketTypeChangeEvent + * @param {String} newtype + * @param {discord.User} user + * @param {discord.TextChannel} channel + * @param {discord.Guild} guild + * @param {Date} date + * @param {{name:String,status:"open"|"closed"|"deleted"|"reopened",ticketOptions:configParser.OTTicketOptions}} ticketdata + */ + /** * @callback CommandEvent * @param {OTCommandType} type @@ -328,6 +402,21 @@ const onTicketRemove = (callback) => { ticketRemoveListeners.push(callback) } +/**@param {TicketActionEvent} callback */ +const onTicketClaim = (callback) => { + ticketClaimListeners.push(callback) +} + +/**@param {TicketActionEvent} callback */ +const onTicketUnclaim = (callback) => { + ticketUnclaimListeners.push(callback) +} + +/**@param {TicketTypeChangeEvent} callback */ +const onTicketChange = (callback) => { + ticketChangeListeners.push(callback) +} + /**@param {TranscriptCreationEvent} callback */ const onTranscriptCreation = (callback) => { transcriptCreationListeners.push(callback) @@ -355,6 +444,9 @@ exports.events = { onTicketReopen, onTicketAdd, onTicketRemove, + onTicketClaim, + onTicketUnclaim, + onTicketChange, onTranscriptCreation, onCommand, onReactionRole, diff --git a/core/checker.js b/core/checker.js index edc73db..32311f5 100644 --- a/core/checker.js +++ b/core/checker.js @@ -368,7 +368,7 @@ exports.checker = async () => { //--------------------------| //--------------------------| - var configArray = ["main_color","server_id","auth_token","main_adminroles","prefix","languagefile","credits","status","system","options","messages"] + var configArray = ["main_color","server_id","auth_token","main_adminroles","prefix","languagefile","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") @@ -390,7 +390,6 @@ exports.checker = async () => { createError("'languagefile' | invalid language, more info in the wiki") } - checkType(config.credits,"boolean","credits") //status: checkType(config.status.enabled,"boolean","status/enabled") if (config.status.enabled){ @@ -423,11 +422,6 @@ exports.checker = async () => { createError("'system/closeMode' | the close mode must be adminonly or normal") } - 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){ - checkDiscord("channelid",config.system.transcript_channel,"system/transcript_channel") - } checkType(config.system.showSlashcmdsInHelp,"boolean","system/showSlashcmdsInHelp") //options diff --git a/core/interactionHandlers/buttons/close.js b/core/interactionHandlers/buttons/close.js index 46b7224..4f8bdbf 100644 --- a/core/interactionHandlers/buttons/close.js +++ b/core/interactionHandlers/buttons/close.js @@ -25,16 +25,26 @@ exports.closeCommandRow = new arb() ) .addComponents( new button() - .setCustomId("OTsendTranscript") + .setCustomId("OTreopenTicket") .setDisabled(false) - .setStyle(bs.Secondary) - .setLabel(l.buttons.sendTranscript) - .setEmoji("📄") + .setStyle(bs.Success) + .setLabel(l.buttons.reopen) + .setEmoji("✔") + ) + +exports.closeCommandRowDisabled = new arb() + .addComponents( + new button() + .setCustomId("OTdeleteTicket1") + .setDisabled(true) + .setStyle(bs.Danger) + .setLabel(l.buttons.delete) + .setEmoji("✖️") ) .addComponents( new button() .setCustomId("OTreopenTicket") - .setDisabled(false) + .setDisabled(true) .setStyle(bs.Success) .setLabel(l.buttons.reopen) .setEmoji("✔") diff --git a/core/interactionHandlers/embeds/commands.js b/core/interactionHandlers/embeds/commands.js index 990bd23..b2ec6c2 100644 --- a/core/interactionHandlers/embeds/commands.js +++ b/core/interactionHandlers/embeds/commands.js @@ -136,4 +136,17 @@ exports.renameEmbed = (renamer,newname) => { .setDescription("Loading...") .setFooter({text:author.tag,iconURL:author.displayAvatarURL()}) } +} + +/** + * + * @param {discord.User} changer + * @param {String} newtype + * @returns {discord.EmbedBuilder} + */ +exports.changeEmbed = (changer,newtype) => { + return new embed() + .setTitle("🔄 "+l.commands.changeTitle.replace("{0}",newtype)) + .setColor(mc) + .setFooter({text:changer.tag,iconURL:changer.displayAvatarURL()}) } \ No newline at end of file diff --git a/core/interactionHandlers/handlers/accepted/deleting.js b/core/interactionHandlers/handlers/accepted/deleting.js index 900db9b..091d36c 100644 --- a/core/interactionHandlers/handlers/accepted/deleting.js +++ b/core/interactionHandlers/handlers/accepted/deleting.js @@ -50,8 +50,8 @@ module.exports = () => { } }) - interaction.channel.send({embeds:[bot.embeds.commands.deleteEmbed(interaction.user)]}) await interaction.message.edit({components:[bot.buttons.close.openRowDisabled]}) + await interaction.channel.send({embeds:[bot.embeds.commands.deleteEmbed(interaction.user)]}) await require("../../../ticketActions/ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"delete",false,true) deleteTicketButtonChecker = false }) @@ -90,8 +90,10 @@ module.exports = () => { } }) - interaction.channel.send({embeds:[bot.embeds.commands.deleteEmbed(interaction.user)]}) - await require("../../../ticketActions/ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"deletenotranscript",false,true) + await interaction.message.edit({components:[bot.buttons.close.closeCommandRowDisabled]}) + await interaction.channel.send({embeds:[bot.embeds.commands.deleteEmbed(interaction.user)]}) + await require("../../../ticketActions/ticketCloser").NEWcloseTicket(interaction.member,interaction.channel,prefix,"delete",false,true) deleteTicketButtonChecker1 = false + }) } \ No newline at end of file diff --git a/core/interactionHandlers/handlers/handlers.js b/core/interactionHandlers/handlers/handlers.js index 5dea097..c2c015b 100644 --- a/core/interactionHandlers/handlers/handlers.js +++ b/core/interactionHandlers/handlers/handlers.js @@ -1,6 +1,5 @@ module.exports = () => { require("./firstmsg")() - require("./sendTranscript")() require("./verifyBars")() //accepted diff --git a/core/interactionHandlers/handlers/sendTranscript.js b/core/interactionHandlers/handlers/sendTranscript.js deleted file mode 100644 index 6ac442c..0000000 --- a/core/interactionHandlers/handlers/sendTranscript.js +++ /dev/null @@ -1,46 +0,0 @@ -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 storage = bot.storage -const hiddendata = bot.hiddenData -const embed = discord.EmbedBuilder -const mc = config.main_color - -const button = discord.ButtonBuilder -const arb = discord.ActionRowBuilder -const bs = discord.ButtonStyle - - -module.exports = () => { - client.on("interactionCreate",async (interaction) => { - if (!interaction.isButton()) return - if (interaction.customId != "OTsendTranscript") return - - try { - interaction.deferUpdate() - } catch{} - const tsmsg = await interaction.channel.send({embeds:[bot.embeds.commands.sendTranscriptEmbed(false,interaction.channel,interaction.user)]}) - - const channelmessages = await interaction.channel.messages.fetch() - - channelmessages.sweep((msgSweep) => { - return msgSweep.author.id == client.user.id - }) - - var fileattachment = await require("../../transcript").createTranscript(channelmessages,interaction.channel) - - if (fileattachment == false){ - log("system","internal error: transcript is not created!") - tsmsg.edit({embeds:[bot.errorLog.serverError(l.errors.somethingWentWrongTranscript)]}) - return - } - - try { - tsmsg.edit({embeds:[bot.embeds.commands.sendTranscriptEmbed(true,interaction.channel,interaction.user)],files:[fileattachment]}) - }catch{} - }) -} \ No newline at end of file diff --git a/core/languageManager.js b/core/languageManager.js index 31641de..639d40b 100644 --- a/core/languageManager.js +++ b/core/languageManager.js @@ -16,6 +16,7 @@ else if (config.languagefile.startsWith("arabic")) localLanguage = require("../l else if (config.languagefile.startsWith("spanish")) localLanguage = require("../language/spanish.json") else if (config.languagefile.startsWith("portuguese")) localLanguage = require("../language/portuguese.json") else if (config.languagefile.startsWith("italian")) localLanguage = require("../language/italian.json") +else if (config.languagefile.startsWith("danish")) localLanguage = require("../language/danish.json") const errorLog = async () => { diff --git a/core/slashSystem/slashEnable.js b/core/slashSystem/slashEnable.js index 299b5e7..b587f7b 100644 --- a/core/slashSystem/slashEnable.js +++ b/core/slashSystem/slashEnable.js @@ -32,8 +32,8 @@ module.exports = async () => { //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 12")+" commands ready! (this can take up to 40 seconds)") - if (readystats >= 12){ + process.stdout.write("[status] there are "+chalk.blue(readystats+" out of 13")+" commands ready! (this can take up to 40 seconds)") + if (readystats >= 13){ const fs = require("fs") fs.writeFileSync("./storage/slashcmdEnabled.txt","true") console.log(chalk.green("\nready!")) @@ -245,4 +245,23 @@ module.exports = async () => { readystats++ }) + //category + client.application.commands.create({ + name:"change", + description:"Change ticket type.", + defaultPermission:true, + type:act.ChatInput, + options:[ + { + type:acot.String, + name:"type", + description:"The new ticket type.", + required:true, + choices:choices + } + ] + },sid).then(() => { + readystats++ + }) + } \ No newline at end of file diff --git a/core/ticketActions/ticketCloser.js b/core/ticketActions/ticketCloser.js index ad1ff99..61d76ad 100755 --- a/core/ticketActions/ticketCloser.js +++ b/core/ticketActions/ticketCloser.js @@ -49,7 +49,7 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode,reason,nomessage) => var enableTranscript = true var deleteRequired = false - if (mode == "delete"){ + if (mode == "delete" || mode == "deletenotranscript"){ //delete //check perms if (!guild) return @@ -88,12 +88,6 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode,reason,nomessage) => if (!id) return false - try{ - if (config.system.enable_DM_Messages){ - 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"){ @@ -196,14 +190,6 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode,reason,nomessage) => .setLabel(l.buttons.delete) .setEmoji("✖️") ) - .addComponents( - new discord.ButtonBuilder() - .setCustomId("OTsendTranscript") - .setDisabled(false) - .setStyle(discord.ButtonStyle.Secondary) - .setLabel(l.buttons.sendTranscript) - .setEmoji("📄") - ) .addComponents( new discord.ButtonBuilder() .setCustomId("OTreopenTicket") @@ -237,117 +223,26 @@ exports.NEWcloseTicket = async (member,channel,prefix,mode,reason,nomessage) => if (!id) return false - try{ - if (config.system.enable_DM_Messages){ - member.send({embeds:[bot.errorLog.custom(l.messages.closedTicketDmTitle,l.messages.closedTicketDmDescription+"\n\n**reason:** "+newReason,":ticket:",config.main_color)]}) - } - } - catch{log("system","can't send DM to member, member doesn't allow dm's")} }) - }else if (mode == "deletenotranscript"){ - //delete with no transcript - //check perms - if (!guild) return - if (!permsChecker.command(user.id,guild.id)){ - permsChecker.sendUserNoPerms(user) - return - } - - //start delete proccess - enableTranscript = false - deleteRequired = true - if (!nomessage){ - await channel.send({content:"**"+l.messages.gettingdeleted+"**"}) - } - log("system","deleted a ticket",[{key:"user",value:user.tag},{key:"ticket",value:channel.name}]) - - if (!isDatabaseError) storage.set("ticketStorage",getuserID,Number(storage.get("ticketStorage",getuserID)) - 1) - - //getID & send DM & send api event - await channel.messages.fetchPinned().then(msglist => { - var firstmsg = msglist.last() - if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false - const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) - const ticketId = hiddendata.data.find(d => d.key == "type").value - const ticketData = require("../utils/configParser").getTicketById(ticketId,true) - - require("../api/modules/events").onTicketDelete(user,channel,guild,new Date(),{name:channel.name,status:"deleted",ticketOptions:ticketData}) - - const id = hiddendata.data.find(d => d.key == "openerid").value - - if (!id) return false - - try{ - if (config.system.enable_DM_Messages){ - 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")} - }) } const transcriptHandler = async () => { - if (enableTranscript == true && mode != "deletenotranscript"){ - //transcript messages - const transcriptReason = (mode == "close") ? "**"+l.messages.reason+":** "+newReason : "**"+l.messages.reason+":** "+l.messages.none - const closedByPrefix = (mode.startsWith("delete")) ? l.messages.deletedby : l.messages.closedby + if (!bot.tsconfig.sendTranscripts.enableChannel && !bot.tsconfig.sendTranscripts.enableDM) return false - if (config.system.enable_transcript || config.system.enable_DM_transcript){ - const channelmessages = await channel.messages.fetch({cache:true}) - //remove ot bot from transcript - channelmessages.sweep((msgSweep) => {return msgSweep.author.id == client.user.id}) - - var fileattachment = await require("../transcript").createTranscript(channelmessages,channel) - - if (fileattachment == false){log("system","internal error: transcript is not created!");return} - } - - if (config.system.enable_transcript && !require("../api/api.json").disable.transcripts.server){ - const transcriptEmbed = new discord.EmbedBuilder() - .setColor(config.main_color) - .setTitle("📄 "+l.messages.newTranscriptTitle) - .setDescription(transcriptReason) - .setFooter({text:closedByPrefix+": "+user.tag+" | ticket: "+channelname,iconURL:user.displayAvatarURL()}) - - guild.channels.cache.find(c => c.id == config.system.transcript_channel).send({ - embeds:[transcriptEmbed], - files:[fileattachment] - }) - } - - if (config.system.enable_DM_transcript && !require("../api/api.json").disable.transcripts.dm){ - const transcriptEmbed = new discord.EmbedBuilder() - .setColor(config.main_color) - .setTitle("📄 "+l.messages.newTranscriptTitle) - .setDescription(transcriptReason) - .setFooter({text:closedByPrefix+": "+user.tag+" | ticket: "+channelname,iconURL:user.displayAvatarURL()}) - - if (!isDatabaseError) ticketOpener.send({ - embeds:[transcriptEmbed], - files:[fileattachment] - }) - } - } + const APIEvents = require("../api/modules/events") + const messages = await channel.messages.fetch({cache:true}) + await require("../transcriptSystem/manager")(messages,guild,channel,user,reason) + APIEvents.onTranscriptCreation(messages,channel,guild,new Date()) } const deleteHandler = async () => { if (deleteRequired){ - //const timer = () => {return new Promise((resolve,reject) => { - // setTimeout(() => {resolve(true)},7000) - //})} - //await timer() - pendingDelete.shift() - await channel.delete() - - //setTimeout(async () => { - // pendingDelete.shift() - // await channel.delete() - //},6000) + await channel.delete() } } - await transcriptHandler() + if (mode == "delete" || mode == "deletenotranscript") await transcriptHandler() deleteHandler() } \ No newline at end of file diff --git a/core/ticketActions/ticketOpener.js b/core/ticketActions/ticketOpener.js index 3ff877b..9af64eb 100755 --- a/core/ticketActions/ticketOpener.js +++ b/core/ticketActions/ticketOpener.js @@ -66,7 +66,7 @@ module.exports = () => { 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){ + if (currentTicketOptions.enableDmOnOpen){ interaction.member.send({embeds:[bot.errorLog.custom(l.messages.newTicketDmTitle,currentTicketOptions.message,":ticket:",config.main_color)]}) } } diff --git a/core/transcript.js b/core/transcript.js deleted file mode 100755 index f0829fe..0000000 --- a/core/transcript.js +++ /dev/null @@ -1,75 +0,0 @@ -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 hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) - const ticketId = hiddendata.data.find(d => d.key == "type") - - const id = hiddendata.data.find(d => d.key == "openerid").value - - 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.attachmentBuilder` - */ - -exports.createTranscript = async (messagecollection,channel) => { - const ticketuserdata = await getUserInfo(channel) - - require("./api/modules/events").onTranscriptCreation(messagecollection,channel,channel.guild,new Date()) - try { - const cd = new Date() - const months = ["January","February","March","April","May","June","July","August","September","October","November","December"] - const dateString = cd.getDate()+" "+months[cd.getMonth()-1]+" "+cd.getFullYear()+" - "+cd.getHours()+":"+cd.getMinutes()+":"+cd.getSeconds() - 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) - - if (msg.content){var content = msg.content}else{var content = "*empty message*"} - - const msgstats = "files: "+msg.attachments.size+", embeds: "+msg.embeds.length - filearray.push("["+timestamp.getDate()+"/"+timestamp.getMonth()+"/"+timestamp.getFullYear()+", "+timestamp.getHours()+":"+timestamp.getMinutes()+":"+timestamp.getSeconds()+"|"+msg.author.tag+"] ["+msgstats+"]\n"+content+"\n") - }) - - if (filearray.length < 2) filearray.push("transcript is empty") - const filestring = filearray.join("\n") - const filebuff = Buffer.from(filestring,"utf-8") - return new discord.AttachmentBuilder(filebuff,{name:"transcript_"+ticketuserdata.ticketname+".txt",description:"An Open Ticket transcript"}) - }catch(err){ - console.log("[error] "+err) - return false - } -} \ No newline at end of file diff --git a/core/transcriptSystem/communication/compileJson.js b/core/transcriptSystem/communication/compileJson.js new file mode 100644 index 0000000..6aa1ba4 --- /dev/null +++ b/core/transcriptSystem/communication/compileJson.js @@ -0,0 +1,119 @@ +const discord = require('discord.js') + +const bot = require("../../../index") +const tsconfig = bot.tsconfig +const tsembeds = require("../embeds") +const tsdb = require("../tsdb") + +const otversion = require("../../../package.json").version +const version = require("../info.json").version + +/**@typedef {{style:{enableCustomBackground:Boolean, backgroundModus:"color"|"image", backgroundData:String, titleColor:String}, bot:{name:String, id:Number, pfp:String}, ticket:{creatorname:String, creatorid:Number, closedtime:Number, openedtime:Number}}} OThtsDataOption */ + + +/** + * + * @param {discord.Guild} guild + * @param {discord.Channel} channel + * @param {discord.User} user + * @param {discord.Message[]} messagesInv + * @param {OThtsDataOption} data + */ +exports.compile = (guild,channel,user,messagesInv,data) => { + const messages = messagesInv.reverse() + var invisibleMessages = 0 + + const rawfiles = messages.filter((m) => Array.from(m.attachments).length > 0) + var fileAmount = 0 + rawfiles.forEach((msg) => { + fileAmount = fileAmount + Array.from(msg.attachments).length + }) + + const messagesArray = [] + messages.forEach((msg) => { + if (msg.content || msg.embeds.length > 0 || msg.attachments.toJSON().length > 0){ + + const embedArray = [] + const fileArray = [] + + msg.attachments.forEach((file) => { + fileArray.push({ + name:file.name, + type:file.contentType, + size:file.size.toString()+" bytes", + url:file.url + }) + }) + + msg.embeds.forEach((embed) => { + if (embed.description){ + var desc = bot.hiddenData.removeHiddenData(embed.description).description + }else{var desc = false} + + embedArray.push({ + title:embed.title || false, + description:desc, + authorimg:((embed.author && embed.author.iconURL) ? embed.author.iconURL : false), + authortext:(embed.author ? embed.author.name : false), + footerimg:((embed.footer && embed.footer.iconURL) ? embed.footer.iconURL : false), + footertext:(embed.footer ? embed.footer.text : false), + color:embed.hexColor, + image:((embed.image && embed.image.url) ? embed.image.url : false), + thumbnail:((embed.thumbnail && embed.thumbnail.url) ? embed.thumbnail.url : false), + url:(embed.url ? embed.url : false) + }) + }) + + + messagesArray.push({ + author:{ + name:msg.author.tag, + id:Number(msg.author.id), + color:msg.author.hexAccentColor || "#ffffff", + pfp:msg.author.displayAvatarURL() + }, + content:msg.content || "", + timestamp:msg.createdTimestamp, + embeds:embedArray, + files:fileArray + }) + }else {invisibleMessages++} + }) + + const result = { + version,otversion, + style:{ + backgroundData:data.style.backgroundData || "", + backgroundModus:data.style.backgroundModus || "", + enableCustomBackground:data.style.enableCustomBackground || false, + titleColor:data.style.titleColor || "#F8BA00" + }, + bot:{ + name:data.bot.name || "Open Ticket", + id:Number(data.bot.id) || 0, + pfp:data.bot.pfp || "dj-dj.be/wp-content/uploads/2022/07/profielfoto-blauw-wit.png?size=128" + }, + ticket:{ + name:channel.name, + id:Number(channel.id), + + guildname:guild.name, + guildid:Number(guild.id), + + creatorname:data.ticket.creatorname, + creatorid:Number(data.ticket.creatorid), + closedbyname:user.tag, + closedbyid:Number(user.id), + + closedtime:data.ticket.closedtime, + openedtime:data.ticket.openedtime, + + messages:Array.from(messages).length-invisibleMessages, + files:fileAmount + }, + messages:messagesArray + } + + + return result +} \ No newline at end of file diff --git a/core/transcriptSystem/communication/index.js b/core/transcriptSystem/communication/index.js new file mode 100644 index 0000000..64235d3 --- /dev/null +++ b/core/transcriptSystem/communication/index.js @@ -0,0 +1,29 @@ +const axios = require("axios").default +const discord = require('discord.js') + +const bot = require("../../../index") +const tsconfig = bot.tsconfig +const tsembeds = require("../embeds") +const tsdb = require("../tsdb") + +/**@typedef {{status:"success"|"error", id:String, time:Number, estimated:{lastdump: Number, processtime:Number}, transcriptstatus:{value:2, data:{fetchedmsgs:true, uploaded:true, inqueue:true, processed:false, waiting:false, available:false}}}} OTuploadResponse */ + +/** + * @param {Object} json + * @returns {Promise} + */ +exports.upload = async (json) => { + return new Promise(async (resolve,reject) => { + const data = encodeURIComponent(JSON.stringify(json)) + + try { + const res = await axios.get("https://api.transcripts.dj-dj.be/upload?auth=openticketTRANSCRIPT1234&version=1.0.0&data="+data) + if (res.status != 200) resolve(false) + + resolve(res.data) + }catch{ + console.log("failed transcript upload!") + resolve(false) + } + }) +} \ No newline at end of file diff --git a/core/transcriptSystem/communication/template.json b/core/transcriptSystem/communication/template.json new file mode 100644 index 0000000..5da4aaf --- /dev/null +++ b/core/transcriptSystem/communication/template.json @@ -0,0 +1,67 @@ +{ + "version":"1.0.0", + "otversion":"3.2.0", + "style":{ + "enableCustomBackground":false, + "backgroundModus":"color OR image", + "backgroundData":"#ffffff OR https://www.example.com/image.png", + "titleColor":"#ffffff" + }, + "bot":{ + "name":"DJdj Support Bot", + "id":12345678910, + "pfp":"https://www.example.com/image.png" + }, + "ticket":{ + "name":"support-DJj123dj", + "id":12345678910, + + "guildname":"DJdj Development", + "guildid":12345678910, + + "creatorname":"DJj123dj#1706", + "creatorid":12345678910, + "closedbyname":"DJj123dj#1706", + "closedbyid":12345678910, + + "closedtime":12345678910, + "openedtime":12345678910, + + "messages":1, + "files":1 + }, + "messages":[ + { + "author":{ + "name":"DJj123dj#1706", + "id":12345678910, + "color":"#ffffff", + "pfp":"https://www.example.com/image.png" + }, + "content":"string or FALSE", + "timestamp":12345678910, + "embeds":[ + { + "title":"string or FALSE", + "description":"string or FALSE", + "authorimg":"https://www.example.com/image.png or FALSE", + "authortext":"string or FALSE", + "footerimg":"https://www.example.com/image.png or FALSE", + "footertext":"string or FALSE", + "color":"#ffffff", + "image":"https://www.example.com/image.png or FALSE", + "thumbnail":"https://www.example.com/image.png or FALSE", + "url":"https://www.example.com/image.png or FALSE" + } + ], + "files":[ + { + "name":"image.png", + "type":"PNG", + "size":"1MB", + "url":"https://www.example.com/image.png" + } + ] + } + ] +} \ No newline at end of file diff --git a/core/transcriptSystem/embeds.js b/core/transcriptSystem/embeds.js new file mode 100644 index 0000000..e849058 --- /dev/null +++ b/core/transcriptSystem/embeds.js @@ -0,0 +1,74 @@ +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 +const tsconfig = bot.tsconfig + +/** + * + * @param {String} name + * @param {String} id + * @param {Number} rawprocesstime milliseconds + * @param {discord.User} user + */ +exports.beingprocessed = (name,id,rawprocesstime,user) => { + + const newtime = rawprocesstime + + const processtime = "" + + const embed = new discord.EmbedBuilder() + .setTitle("🧾 Transcript") + .setColor(config.main_color) + .setAuthor({name:user.tag,iconURL:user.displayAvatarURL()}) + .setFooter({text:name}) + + .setDescription("`This transcript is being processed...`\nPlease wait!\n\nEstimated time: "+processtime) + + return embed +} + + +/** + * + * @param {String} name + * @param {String} id + * @param {String} url + * @param {discord.User} user + */ +exports.tsready = (name,id,url,user) => { + const embed = new discord.EmbedBuilder() + .setTitle("🧾 Transcript") + .setColor(config.main_color) + .setAuthor({name:user.tag,iconURL:user.displayAvatarURL()}) + .setFooter({text:name}) + .setURL(url) + + .setDescription("\nThe transcript is available [here]("+url+")\n") + + return embed +} + +/** + * + * @param {String} name + * @param {String} id + * @param {discord.User} user + * @param {undefined|String} err + */ +exports.tserror = (name,id,user,err) => { + const embed = new discord.EmbedBuilder() + .setTitle("❌ Transcript") + .setColor(discord.Colors.Red) + .setAuthor({name:user.tag,iconURL:user.displayAvatarURL()}) + .setFooter({text:name}) + + const errDesc = (typeof err == "string") ? "\n"+err : "" + + embed.setDescription("Something went wrong while creating the HTML transcript.\n\n[possible reasons](https://docs.openticket.dj-dj.be/the-system/transcripts/transcript-errors)"+errDesc) + + return embed +} diff --git a/core/transcriptSystem/info.json b/core/transcriptSystem/info.json new file mode 100644 index 0000000..ea2feef --- /dev/null +++ b/core/transcriptSystem/info.json @@ -0,0 +1,3 @@ +{ + "version":"1.0.0" +} \ No newline at end of file diff --git a/core/transcriptSystem/manager.js b/core/transcriptSystem/manager.js new file mode 100644 index 0000000..0b7179e --- /dev/null +++ b/core/transcriptSystem/manager.js @@ -0,0 +1,139 @@ +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 + +const tsconfig = bot.tsconfig +const tsembeds = require("./embeds") +const tsdb = require("./tsdb") + + +const checkAvailability = async () => { + const axios = require("axios").default + const res = await axios.get("https://transcripts.dj-dj.be/status.txt") + if (!res || !(res.status == 200) || !res.data) return false + + if ((res.data == "online") || (res.data == "1") || (res.data == "true")) return true + else return false +} + +/** + * + * @param {discord.Message[]} messages + * @param {discord.Guild} guild + * @param {discord.TextChannel} channel + * @param {discord.User} user + * @param {String|false} reason + */ +module.exports = async (messages,guild,channel,user,reason) => { + require("../api/modules/events").onTranscriptCreation(messages,channel,guild,new Date()) + const msglist = await channel.messages.fetchPinned() + + const chName = channel.name + const chId = channel.id + + /**@param {discord.Collection>} msglist*/ + const asyncmanager = async (msglist) => { + var firstmsg = msglist.last() + + if (firstmsg == undefined || firstmsg.author.id != client.user.id) return false + const hiddendata = bot.hiddenData.readHiddenData(firstmsg.embeds[0].description) + const ticketId = hiddendata.data.find(d => d.key == "type") + + const id = hiddendata.data.find(d => d.key == "openerid").value + const opentime = new Date(Number(hiddendata.data.find(d => d.key == "createdms").value)) + + const ticketopener = client.users.cache.find(u => u.id == id) + + + const JSONDATA = require("./communication/compileJson").compile(guild,channel,user,messages,{ + style:{ + titleColor:tsconfig.style.titleColor, + enableCustomBackground:tsconfig.style.background.enableCustomBackground, + backgroundModus:tsconfig.style.background.backgroundModus, + backgroundData:tsconfig.style.background.backgroundData + }, + bot:{ + name:client.user.username, + id:client.user.id, + pfp:client.user.displayAvatarURL() + }, + ticket:{ + creatorid:ticketopener.id, + creatorname:ticketopener.tag, + openedtime:opentime.getTime(), + closedtime:new Date().getTime() + } + }) + + if (!await checkAvailability()){ + const attachment = await require("./oldTranscript").createTranscript(messages,channel) + const errembed = tsembeds.tserror(chName,chId,user) + + if (tsconfig.sendTranscripts.enableChannel){ + /**@type {discord.TextChannel|undefined} */ + const tc = guild.channels.cache.find((c) => c.id == tsconfig.sendTranscripts.channel) + + if (!tc) return + tc.send({embeds:[errembed],files:[attachment]}) + } + return + } + + const TSdata = await require("./communication/index").upload(JSONDATA) + if (!TSdata) return false + + if (TSdata.status == "success"){ + const url = "https://transcripts.dj-dj.be/t/"+TSdata.time+"_"+TSdata.id+".html" + + //calculate estimated time + const lastDumpTime = (new Date(TSdata.estimated.lastdump).getTime()) + const dumpLoopTime = 15000 + const nextDump = new Date(lastDumpTime+dumpLoopTime) + const processtime = TSdata.estimated.processtime+6000 //6sec extra time for overflow + + const finaltime = new Date(nextDump.getTime()+processtime) + const duration = finaltime.getTime()-new Date().getTime() + + //waiting + if (tsconfig.sendTranscripts.enableChannel){ + /**@type {discord.TextChannel|undefined} */ + const tc = guild.channels.cache.find((c) => c.id == tsconfig.sendTranscripts.channel) + + if (!tc) return + const embed = tsembeds.beingprocessed(chName,chId,finaltime,user) + var msg = await tc.send({embeds:[embed]}) + }else {var msg = false} + + //ready + setTimeout(() => { + if (msg){ + msg.edit({embeds:[tsembeds.tsready(chName,chId,url,user)]}) + } + + if (tsconfig.sendTranscripts.enableDM){ + if (!user) return + const embed = tsembeds.tsready(chName,chId,url,user) + try { + user.send({embeds:[embed]}) + }catch{} + } + },duration) + }else{ + const attachment = await require("./oldTranscript").createTranscript(messages,channel) + const errembed = tsembeds.tserror(chName,chId,user,"`error type: transcript API error`") + + if (tsconfig.sendTranscripts.enableChannel){ + /**@type {discord.TextChannel|undefined} */ + const tc = guild.channels.cache.find((c) => c.id == tsconfig.sendTranscripts.channel) + + if (!tc) return + tc.send({embeds:[errembed],files:[attachment]}) + } + } + } + asyncmanager(msglist) +} \ No newline at end of file diff --git a/core/transcriptSystem/oldTranscript.js b/core/transcriptSystem/oldTranscript.js new file mode 100755 index 0000000..7459480 --- /dev/null +++ b/core/transcriptSystem/oldTranscript.js @@ -0,0 +1,38 @@ +const discord = require('discord.js') +const bot = require('../../index') +const client = bot.client +const config = bot.config +const l = bot.language + +/** + * + * @param {discord.Message[]} messagecollection + * @returns new `discord.attachmentBuilder` + */ + +exports.createTranscript = async (messagecollection) => { + try { + 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.getHours()+":"+cd.getMinutes()+":"+cd.getSeconds() + const filearray = ["BACKUP TRANSCRIPT:\n"] + + messagecollection.reverse() + + messagecollection.forEach((msg) => { + const timestamp = new Date(msg.createdTimestamp) + + if (msg.content){var content = msg.content}else{var content = "*empty message*"} + + const msgstats = "files: "+msg.attachments.size+", embeds: "+msg.embeds.length + filearray.push("["+timestamp.getDate()+"/"+timestamp.getMonth()+"/"+timestamp.getFullYear()+", "+timestamp.getHours()+":"+timestamp.getMinutes()+":"+timestamp.getSeconds()+"|"+msg.author.tag+"] ["+msgstats+"]\n"+content+"\n") + }) + + if (filearray.length < 2) filearray.push("transcript is empty") + const filestring = filearray.join("\n") + const filebuff = Buffer.from(filestring,"utf-8") + return new discord.AttachmentBuilder(filebuff,{name:"backuptranscript.txt",description:"Open Ticket transcript"}) + }catch{ + return false + } +} \ No newline at end of file diff --git a/core/transcriptSystem/tsdb.js b/core/transcriptSystem/tsdb.js new file mode 100644 index 0000000..2ad725e --- /dev/null +++ b/core/transcriptSystem/tsdb.js @@ -0,0 +1,71 @@ +const fs = require("fs") +const location = "./storage/tsdatabase.json" + + +/**@returns {[{category:String, key:String, value:String}]}*/ +function getData(){ + if (fs.existsSync(location)){ + return JSON.parse(fs.readFileSync(location).toString()) + }else{ + fs.writeFileSync(location,"[]") + return [] + } +} +/**@param {[{category:String, key:String, value:String}]} data*/ +function setData(data){ + fs.writeFileSync(location,JSON.stringify(data,null,"\t")) +} + +exports.set = (category,key,value) => { + const currentData = getData() + const exists = currentData.find((d) => (d.category == category) && (d.key == key)) ? true : false + var newData = [] + if (exists){ + currentData.forEach((d,i) => { + if (d.category == category && d.key == key){ + newData.push({category,key,value}) + }else{ + newData.push(d) + } + }) + }else{ + currentData.push({category,key,value}) + newData = currentData + } + + setData(newData) + return exists +} +/** + * @param {String} category + * @param {String} key + * @returns {String|false} + */ +exports.get = (category,key) => { + const currentData = getData() + const tempresult = currentData.find((d) => (d.category == category) && (d.key == key)) + const result = tempresult ? tempresult.value : false + return result +} +/** + * @param {String} category + * @param {String} key + * @param {String} value + */ +exports.delete = (category,key) => { + const currentData = getData() + const exists = currentData.find((d) => (d.category == category) && (d.key == key)) ? true : false + var newData = [] + if (exists){ + currentData.forEach((d,i) => { + if (!(d.category == category && d.key == key)){ + newData.push(d) + } + }) + }else{ + newData = currentData + } + + setData(newData) + return exists +} \ No newline at end of file diff --git a/core/utils/getEmbed.js b/core/utils/getEmbed.js index 1abb837..85de281 100644 --- a/core/utils/getEmbed.js +++ b/core/utils/getEmbed.js @@ -35,7 +35,10 @@ exports.createEmbed = (id) => { const embed = new discord.EmbedBuilder() .setTitle(data.name) if (data.enableFooter) embed.setFooter({text:data.footer}) - if (data.enableThumbnail) embed.setThumbnail(data.thumbnail) + + try { + if (data.enableThumbnail) embed.setThumbnail(data.thumbnail) + }catch{bot.errorLog.log("info","THUMBNAIL FAILED TO LOAD, probably invalid url!")} if (data.enableCustomColor){ embed.setColor(data.color) diff --git a/index.js b/index.js index 94ce9d2..d072fa9 100644 --- a/index.js +++ b/index.js @@ -69,8 +69,13 @@ const language = require("./core/languageManager").language exports.language = language if (process.argv.some((v) => v == "--debug")) console.log("[TEMP_DEBUG]","loaded language") + const config = tempconfig exports.config = config + +const tsconfig = require("./transcriptconfig.json") +exports.tsconfig = tsconfig + if (process.argv.some((v) => v == "--debug")) console.log("[TEMP_DEBUG]","loaded config") exports.storage = require('./core/dynamicdatabase/storage') if (process.argv.some((v) => v == "--debug")) console.log("[TEMP_DEBUG]","loaded storage") @@ -211,6 +216,7 @@ if (process.argv[2] && process.argv[2].startsWith("slash")){ require("./commands/reopen")() require("./commands/claim")() require("./commands/unclaim")() + require("./commands/change")() this.errorLog.log("debug","LOADING CORE") //core diff --git a/language/danish.json b/language/danish.json new file mode 100644 index 0000000..e96b4dd --- /dev/null +++ b/language/danish.json @@ -0,0 +1,83 @@ +{ + "errors":{ + "missingArgsTitle":"Ugyldige argumenter", + "missingArgsDescription":"Manglende argumenter", + "noPermsTitle":"Ingen adgang", + "noPermsDescription":"Du har ikke adgang til denne kommando", + "noPermsDelete":"Kun administrators kan slette tickets", + "chooseFromListTitle":"Ugyldig ID", + "chooseFromListDescription":"Vælg et ID nedenunder", + "boterror":"Bot Fejl!", + "notInTicketTitle":"Du er ikke i en ticket!", + "notInTicketDescription":"Denne kommando fungere kun i tickets!", + "ticketDoesntExist":"Denne ticket eksistere ikke mere!", + "roleDoesntExist":"Denne rolle eksistere ikke mere!", + "anotherOption":"Dette er ikke en ticket, men noget andet!", + "maxAmountTitle":"For mange tickets er blevet oprettet!", + "maxAmountDescription":"Du har for mange tickets åbne!\nSå luk dem hvis du gerne vil oprette nye!", + "somethingWentWrong":"**Noget gik galt**\nKontakt en udvikler!", + "somethingWentWrongTranscript":"Noget gik galt med transcript!**\nKontakt en udvikler!" + }, + "commands":{ + "userAddedTitle":"Tilføjer {0} til denne ticket!", + "userRemovedTitle":"Fjernet {0} fra denne ticket!", + "renameTitle":"Ændret navnet til{0}!", + "closeTitle":"Closed this ticket!", + "deleteTitle":"Fjerner ticketen", + "reopenTitle":"Genåbnede denne ticket", + "claimTitle":"Denne ticket er blevet taget af {0}", + "unclaimTitle":"Denne ticket er nu tilgængelig!", + + "ticketWarning":"Emebeddet er i beskeden nedenunder", + "maxTicketWarning":"**Fejl:** _Du kan kun oprettre {0} ticket adgangen!_" + }, + "helpMenu":{ + "title":"Tilgængelig kommandoer:", + "header1":"**Gå til {0} For at oprette en ticket!**\n\n", + "header2":"**Skriv kommandoen `/new` eller `/ticket` for at oprette en ticket!**\n\n", + + "msgCmd":"Lav en embed med knapper (admins kun)", + "renameCmd":"Ændre navnet (ingen mellemrum)", + "closeCmd":"Luk denne ticket", + "deleteCmd":"Fjern denne ticket", + "addCmd":"Tilføj en person til ticketen", + "removeCmd":"Fjern en person fra ticketen", + "reopenCmd":"Genåben en ticket efter den har været lukket" + }, + "buttons":{ + "close":"Luk ticket", + "delete":"Fjern ticket", + "reopen":"Genåben ticket", + "sendTranscript":"Transcript", + "closeWithReason":"Luk med grundlag" + }, + "messages":{ + "reopenTitle":"Genåbener denne ticket", + "reopenDescription":"Du kan nu skrive igen", + "closedTitle":"Lukker ticketen!", + "closedDescription":"Kun administrators kan skrive lige nu!\n\n*Klik på knappen nedenunder for at slette eller genåbne ticketen!*", + "createdTitle":"Ticket oprettet!", + "createdDescription":"Din ticket er oprettet!", + + "newTicketDmTitle":"Ny Ticket!", + "closedTicketDmTitle":"Ticket Lukket!", + "deletedTicketDmTitle":"Ticket Fjernet!", + "closedTicketDmDescription":"Din ticket er blevet lukket!", + "deletedTicketDmDescription":"Din ticket er blevet fjernet!", + "reopenTicketDmTitle":"Ticket Genåbnet!", + "reopenTicketDmDescription":"Din ticket er blevet genåbent!", + "newTranscriptTitle":" En ny transcript er tilføjet!", + "hereIsTheTranscript":"Følgende transcript:", + + "chooseCategory":"Vælg en kategori:", + "gettingdeleted":"Ticketen slettes..", + + "none":"Ingen", + "reason":"Grundlag", + + "deletedby":"Fjernet af", + "closedby":"Lukket af", + "modalreason":"Hvad er grundlaget for lukkens af denne ticket?", + "chooseATicket": "Vælg en ticket" + } +} \ No newline at end of file diff --git a/language/english.json b/language/english.json index 480d7f4..b57007b 100644 --- a/language/english.json +++ b/language/english.json @@ -27,6 +27,7 @@ "reopenTitle":"Re-Opened this ticket!", "claimTitle":"This ticket is now claimed to {0}", "unclaimTitle":"This ticket isn't claimed anymore!", + "changeTitle":"Changed ticket type to {0}!", "ticketWarning":"The embed is in the message below!", "maxTicketWarning":"**Warning:** _You can only create {0} ticket(s) at a time!_" diff --git a/language/german.json b/language/german.json index a555b6c..ea786bf 100644 --- a/language/german.json +++ b/language/german.json @@ -69,9 +69,8 @@ "deletedTicketDmTitle":"Ticket löschen!", "closedTicketDmDescription":"Ihr Ticket ist geschlossen!", "deletedTicketDmDescription":"Ihr Ticket ist gelöscht!", - "newTranscriptTitle":"Eine neue Transscript finden Sie hier!", - "newTranscriptDescription":"Die Abschrift finden Sie in der obigen Textdatei!", - "hereIsTheTranscript":"Hier ist das Transscript:", + "newTranscriptTitle":"Eine neue Transcript finden Sie hier!", + "hereIsTheTranscript":"Hier ist das Transcript:", "chooseCategory":"Wähle eine Kategorie:", diff --git a/language/slashcmds/slash.json b/language/slashcmds/slash.json index a3b8f56..30231a3 100644 --- a/language/slashcmds/slash.json +++ b/language/slashcmds/slash.json @@ -114,26 +114,37 @@ "it":"Rinomina il canale di un ticket." }, "claim":{ - "en-GB":"", - "en-US":"", - "nl":"", - "ro":"", - "de":"", - "cs":"", - "fr":"", - "es-ES":"", - "it":"" + "en-GB":"Claim a ticket.", + "en-US":"Claim a ticket.", + "nl":"Claim een ticket.", + "ro":" ", + "de":" ", + "cs":" ", + "fr":" ", + "es-ES":" ", + "it":" " }, "unclaim":{ - "en-GB":"", - "en-US":"", - "nl":"", - "ro":"", - "de":"", - "cs":"", - "fr":"", - "es-ES":"", - "it":"" + "en-GB":"Un-claim a ticket.", + "en-US":"Un-claim a ticket.", + "nl":"Ontclaim een ticket.", + "ro":" ", + "de":" ", + "cs":" ", + "fr":" ", + "es-ES":" ", + "it":" " + }, + "category":{ + "en-GB":"Change ticket type.", + "en-US":"Change ticket type.", + "nl":"Verander ticket type.", + "ro":" ", + "de":" ", + "cs":" ", + "fr":" ", + "es-ES":" ", + "it":" " } } } \ No newline at end of file diff --git a/package.json b/package.json index 9a74f35..6e622fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-ticket", - "version": "3.1.0", + "version": "3.2.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": { @@ -16,9 +16,7 @@ "axios": "^0.27.2", "chalk": "^5.0.1", "discord.js": "^14.7.1", - "express": "^4.17.1", - "node": "^16.10.0", - "node-localstorage": "^2.2.1" + "node": "^16.10.0" }, "repository": { "type": "git", diff --git a/transcriptconfig.json b/transcriptconfig.json new file mode 100644 index 0000000..9fd2f33 --- /dev/null +++ b/transcriptconfig.json @@ -0,0 +1,17 @@ +{ + "sendTranscripts":{ + "enableChannel":false, + "channel":"transcript channel id", + + "enableDM":false + }, + "style":{ + "titleColor":"#F8BA00", + "background":{ + "enableCustomBackground":false, + "backgroundModus":"color OR image", + "backgroundData":"#abc123 OR https://www.example.com/image.png" + + } + } +} \ No newline at end of file