From 206c3d2c0c72aca041b9074193c4af2921c7e329 Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 14:37:39 +0200 Subject: [PATCH 01/10] First djs 13 update --- bot.js | 368 ++++++++++++++------------------------------------------- 1 file changed, 90 insertions(+), 278 deletions(-) diff --git a/bot.js b/bot.js index f7392da..4ed4164 100644 --- a/bot.js +++ b/bot.js @@ -1,284 +1,96 @@ -/* - REPLIT USERS: - Do not use this file. Use replit.js instead. - Read more here: https://v.gd/cdmrpu -*/ - -const Discord = require("discord.js"); -const db = require("quick.db"); +const { Client, Intents } = require("discord.js"); +const client = new Client({ + intents: [ + Intents.FLAGS.GUILDS, + Intents.FLAGS.GUILD_MEMBERS, + Intents.FLAGS.GUILD_MESSAGES, + Intents.FLAGS.DIRECT_MESSAGES, + Intents.FLAGS.DIRECT_MESSAGE_TYPING, + Intents.FLAGS.DIRECT_MESSAGE_REACTIONS + ], + partials: ["CHANNEL"] +}) // not sure about intents, though +const { REST } = require("@discordjs/rest"); +const { Routes } = require("discord-api-types/v9"); const config = require("./config.json"); -const {paste} = require("ubuntu-pastebin"); - -// declare the client -const client = new Discord.Client(); - -// do something when the bot is logged in -client.on("ready", () => { - console.log(`Successfully logged in as ${client.user.tag}.`) - console.log(`Guild ID: ${config.guild}\nLogs channel ID: ${config.log}\nPrefix: ${config.prefix}`) -}) - -client.on("message", async message => { - - const dbTable = new db.table("Tickets"); - - if(message.channel.type === "dm"){ - if(message.author.bot) return; - if(message.content.includes("@everyone") || message.content.includes("@here")) return message.author.send("I'm sorry, but you can not use everyone/here mentions in a modmail thread.") - let active = await dbTable.get(`support_${message.author.id}`); - let guild = client.guilds.cache.get(config.guild); - let channel, found = true; - let user = await dbTable.get(`isBlocked${message.author.id}`); - if(user === true || user === "true") return message.react("❌"); - if(active === null){ - active = {}; - let everyone = guild.roles.cache.get(guild.roles.everyone.id); - let bot = guild.roles.cache.get(config.roles.bot); - await dbTable.add("ticket", 1) - let actualticket = await dbTable.get("ticket"); - channel = await guild.channels.create(`${message.author.username}-${message.author.discriminator}`, { type: 'text', reason: `New modmail thread: #${actualticket}.` }); - channel.setParent(config.ticketCategory); - channel.setTopic(`#${actualticket} | Use ${config.prefix}complete to close this ticket | ${message.author.username}'s ticket`) - config.roles.mod.forEach(mod => { - let modrole = guild.roles.cache.get(mod); - if(!modrole){ - console.warn("I could not fetch this role. Does it exist? Is this the right role ID?") - } else { - channel.createOverwrite(modrole, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - READ_MESSAGE_HISTORY: true - }); - } - }) - channel.createOverwrite(everyone, { - VIEW_CHANNEL: false - }); - channel.createOverwrite(bot, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - READ_MESSAGE_HISTORY: true, - MANAGE_MESSAGES: true - }) - let author = message.author; - const newTicket = new Discord.MessageEmbed() - .setColor("GREEN") - .setAuthor(author.tag, author.avatarURL({dynamic: true})) - .setTitle(`Ticket #${actualticket}`) - .addField("Channel", `<#${channel.id}>`, true) - let supportServer = client.guilds.cache.get(config.guild); - if(config.logs){ - try { - supportServer.channels.cache.get(config.log).send({embed: newTicket}) - } catch(e) { - if(e) supportServer.channels.cache.get(config.log).send(`Ticket #${actualticket} was created by ${author.tag}.`) - } - } - const newChannel = new Discord.MessageEmbed() - .setColor("BLUE").setAuthor(author.tag, author.avatarURL()) - .setDescription(`Ticket #${actualticket} created.\nUser: ${author}\nID: ${author.id}`) - .setTimestamp() - try { - supportServer.channels.cache.get(channel.id).send({embed:newChannel}); - } catch(e) { - supportServer.channels.cache.get(channel.id).send(`This ticket was created by ${author.tag}.`) - } - message.author.send(`Thanks for contacting the support team! We'll get back to you quickly.\nYour ticket ID is #${actualticket}.`) - active.channelID = channel.id; - active.targetID = author.id; - } - channel = client.channels.cache.get(active.channelID); - var text = message.content; - var isPaused = await dbTable.get(`suspended${message.author.id}`); - var isBlocked = await dbTable.get(`isBlocked${message.author.id}`); - if(isPaused === true){ - return message.channel.send("Sorry, but your ticket is currently paused. I'll message you back when the support team unpause it.") - } - if(isBlocked === true) return; // the user is blocked, so we're just gonna move on. - if(message.attachments.size > 0){ - let attachment = new Discord.MessageAttachment(message.attachments.first().url) - try { - client.channels.cache.get(active.channelID).send(`${message.author.username} > ${text}`, {files: [message.attachments.first().url]}) - } catch(e) { - if(e) client.guilds.cache.get(config.guild).channels.cache.get(active.channelID).send(`${message.author.username} > ${text}`, {files: [message.attachments.first().url]}) - } - } else { - try { - client.channels.cache.get(active.channelID).send(`${message.author.username} > ${text}`); - } catch(e) { - if(e) client.guilds.cache.get(config.guild).channels.cache.get(active.channelID).send(`${message.author.username} > ${text}`) - } - } - await dbTable.set(`support_${message.author.id}`, active); - await dbTable.set(`supportChannel_${active.channelID}`, message.author.id); - return; - } - if(message.author.bot) return; - var support = await dbTable.get(`supportChannel_${message.channel.id}`); - let supportServer = client.guilds.cache.get(config.guild); - if(support){ - var support = await dbTable.get(`support_${support}`); - let supportUser = client.users.cache.get(support.targetID); - if(!supportUser) return message.channel.delete(); - - const dbTable2 = new db.table("Tickets"); +const db = require("quick.db"); - // reply (with user and role) - if(message.content.startsWith(`${config.prefix}reply`)){ - var isPause = await dbTable2.get(`suspended${support.targetID}`); - let isBlock = await dbTable2.get(`isBlocked${support.targetID}`); - if(isPause === true) return message.channel.send("This ticket already paused. Unpause it to continue.") - if(isBlock === true) return message.channel.send("The user is blocked. Unblock them to continue or close the ticket.") - var args = message.content.split(" ").slice(1) - let msg = args.join(" "); - message.react("✅"); - if(message.attachments.size > 0){ - let attachment = new Discord.MessageAttachment(message.attachments.first().url) - return supportUser.send(`${message.author.username} > ${msg}`, {files: [message.attachments.first().url]}) - } else { - return supportUser.send(`${message.author.username} > ${msg}`); - } - }; - - // anonymous reply - if(message.content.startsWith(`${config.prefix}areply`)){ - var isPause = await dbTable2.get(`suspended${support.targetID}`); - let isBlock = await dbTable2.get(`isBlocked${support.targetID}`); - if(isPause === true) return message.channel.send("This ticket already paused. Unpause it to continue.") - if(isBlock === true) return message.channel.send("The user is blocked. Unblock them to continue or close the ticket.") - var args = message.content.split(" ").slice(1) - let msg = args.join(" "); - message.react("✅"); - return supportUser.send(`Support Team > ${msg}`); - }; - - // print user ID - if(message.content === `${config.prefix}id`){ - return message.channel.send(`User's ID is **${support.targetID}**.`); - }; - - // suspend a thread - if(message.content === `${config.prefix}pause`){ - var isPause = await dbTable2.get(`suspended${support.targetID}`); - if(isPause === true || isPause === "true") return message.channel.send("This ticket already paused. Unpause it to continue.") - await dbTable.set(`suspended${support.targetID}`, true); - var suspend = new Discord.MessageEmbed() - .setDescription(`⏸️ This thread has been **locked** and **suspended**. Do \`${config.prefix}continue\` to cancel.`) - .setTimestamp() - .setColor("YELLOW") - message.channel.send({embed: suspend}); - return client.users.cache.get(support.targetID).send("Your ticket has been paused. We'll send you a message when we're ready to continue.") - }; - - // continue a thread - if(message.content === `${config.prefix}continue`){ - var isPause = await dbTable2.get(`suspended${support.targetID}`); - if(isPause === null || isPause === false) return message.channel.send("This ticket was not paused."); - await dbTable.delete(`suspended${support.targetID}`); - var c = new Discord.MessageEmbed() - .setDescription("▶️ This thread has been **unlocked**.") - .setColor("BLUE").setTimestamp() - message.channel.send({embed: c}); - return client.users.cache.get(support.targetID).send("Hi! Your ticket isn't paused anymore. We're ready to continue!"); - } - - // block a user - if(message.content.startsWith(`${config.prefix}block`)){ - var args = message.content.split(" ").slice(1) - let reason = args.join(" "); - if(!reason) reason = `Unspecified.` - let user = client.users.fetch(`${support.targetID}`); // djs want a string here - const blocked = new Discord.MessageEmbed() - .setColor("RED").setAuthor(user.tag) - .setTitle("User blocked") - .addField("Channel", `<#${message.channel.id}>`, true) - .addField("Reason", reason, true) - if(config.logs){ - client.channels.cache.get(config.log).send({embed: blocked}) - } - let isBlock = await dbTable2.get(`isBlocked${support.targetID}`); - if(isBlock === true) return message.channel.send("The user is already blocked.") - await dbTable2.set(`isBlocked${support.targetID}`, true); - var c = new Discord.MessageEmbed() - .setDescription("⏸️ The user has been blocked from the modmail. You may now close the ticket or unblock them to continue.") - .setColor("RED").setTimestamp() - message.channel.send({embed: c}); - return; - } - - // complete - if(message.content.toLowerCase() === `${config.prefix}complete`){ - var embed = new Discord.MessageEmbed() - .setDescription(`This ticket will be deleted in **10** seconds...\n:lock: This thread has been locked and closed.`) - .setColor("RED").setTimestamp() - message.channel.send({embed: embed}) - let collection = `Thread ${message.channel.id}\n\n`; - let count = 0; - message.channel.messages.cache.map(msg => { - // could be an error here since message was already defined - let str = msg.content; - let aut = msg.author.username; - collection += `${aut}: ${str}\n\n`; - count++; - }); - paste(collection).then(url => { - let actualticket2 = await dbTable2.get("ticket"); - let u = await client.users.fetch(support.targetID); - let end_log = new Discord.MessageEmbed() - .setColor("RED").setAuthor(u.tag, u.avatarURL()) - .setDescription(`Ticket #${actualticket2} closed.\nUser: ${u.username}\nID: ${userID}`) - .addField("Read the thread", `[Click here](${url})`); - .setTimestamp() - await dbTable2.delete(`support_${userID}`); - setTimeout(() => {message.channel.delete();}, 10000); - supportServer.channels.cache.get(config.log).send({embed:end_log}); - return client.users.cache.get(support.targetID).send(`Thanks for getting in touch with us. If you wish to open a new ticket, feel free to message me.\nYour ticket #${actualticket} has been closed.`) - }) - } - }; +client.once('ready', async () => { + console.log(`Logged in as ${client.user.tag}`); }) -client.on("message", async message => { - if(message.content.startsWith(`${config.prefix}unblock`)){ - if(message.guild.member(message.author).roles.cache.has(config.roles.mod)){ - var args = message.content.split(" ").slice(1); - client.users.fetch(`${args[0]}`).then(async user => { - const dbTable3 = new db.table("Tickets"); - let data = await dbTable3.get(`isBlocked${args[0]}`); - if(data === true){ - await dbTable3.delete(`isBlocked${args[0]}`); - return message.channel.send(`Successfully unblocked ${user.username} (${user.id}) from the modmail service.`); - } else { - return message.channel.send(`${user.username} (${user.id}) is not blocked from the modmail at the moment.`) - } - }).catch(err => { - if(err) return message.channel.send("Unknown user."); - }) - } else { - return message.channel.send("You can not use that."); - } - } -}) +client.login(config.token.bot); -client.on("guildMemberRemove", async member => { - if(config.deleteTicketOnLeave === true){ - const dbTabl = new db.table("Tickets"); - let active = await dbTabl.get(`support_${message.author.id}`); - if(active === null) return; - client.channels.cache.get(active.channelID).delete(); - await dbTabl.delete(`support_${message.author.id}`); - let end_log = new Discord.MessageEmbed() - .setColor("RED").setAuthor(member.tag, member.avatarURL()) - .setDescription(`Ticket #${actualticket} closed because the user has left the server.\nUser: ${member.username}\nID: ${member.id}`) - .setTimestamp() - supportServer.channels.cache.get(config.log).send({embed:end_log}); - return; - } else return; +client.on("messageCreate", async message => { + if(message.author.bot) return; + if(message.content.includes("@everyone") || message.content.includes("@here")) return message.author.send({content: "You're not allowed to use those mentions."}); + console.log("01 no mention, not a bot"); + // Used a new table so it doesn't get messed up with the old one + const table = new db.table("Support13"); + if(message.channel.type === "DM"){ + let active = await table.get(`support_${message.author.id}`); + let block = await table.get(`blocked_${message.author.id}`); + if(block === true) return message.author.send("You are not allowed to use modmail."); + let guild = await client.guilds.fetch(''); // set the server id here + let tc = await guild.channels.fetch(''); // set the category id for your tickets here + let channel, found = true; + if(active === null){ + await table.add("Tickets", 1); + let ticket = await table.get("Tickets"); + channel = await guild.channels.create(`${message.author.username}`, { + type: "GUILD_TEXT", + topic: `#${ticket} | From ${message.author.username}`, + parent: tc, + reason: `${message.author.id} opened a ticket through the modmail service.` + }); + let author = message.author; + const newTicketLog = new MessageEmbed() + .setAuthor(author.tag, author.avatarURL()) + .setDescription(`opened ticket #${ticket}.`) + .setTimestamp() + .setColor("0x6666ff") + let logs = await client.channels.fetch(''); // set the log channel id here + logs.send({embeds: [newTicketLog]}); + message.author.send(`Hello! Thanks for getting in touch. Our support team will get back to you quickly.`); + await table.set(`support_${author.id}`, {channel: channel.id, target: message.author.id, ticket: ticket}); + await table.set(`channel_${channel.id}`, {author: message.author.id}) + let support = await table.get(`support_${message.author.id}`); + let supportchannel = await table.get(`channel_${channel.id}`); + let text = message.content; + await channel.send({content: `${message.author.username} opened this ticket.`}) + await channel.send({content: text}); + return; + }; + channel = guild.channels.cache.get(active.channel); + let text = message.content; + channel.send({content: text}); + } + let activechannel = await table.get(`channel_${message.channel.id}`) + if(activechannel === null) return; // if no channel is binded, nothing happens + let activeuser = await table.get(`support_${activechannel.author}`); + let user = await client.users.fetch(activechannel.author); + let text = message.content; + let args = text.split(" ").slice(1); + let pending = args.join(" "); + let blocked = await table.get(`blocked_${activechannel.author}`); + if(message.content.startsWith(`-r`) || message.content.startsWith(`-reply`)){ + if(blocked === true) return message.channel.send({content: "This user is blocked."}); + await user.send(`${message.author.username}: ${pending}`); + return; + }; + if(message.content === `-id`){ + return message.channel.send({content: `Ticket owner's ID is **${activechannel.author}**.`}); + } + if(message.content === `-b` || message.content === `-block`){ + await table.set(`blocked_${activechannel.author}`, true); + await user.send(`Hi! You can not use modmail anymore.\nOn top of that, you can't contribute or get in touch via any way from now on.`) + message.channel.send(`This user has been blocked from modmail, and other forms of contribution.`); + return; + }; + if(message.content === `-c` || message.content === `-complete`){ + await table.delete(`channel_${message.channel.id}`); + await table.delete(`support_${activechannel.author}`); + await user.send({content: "Hi! Your ticket has been closed.\n\nFeel free to DM me whenever it is needed."}) + message.channel.delete(); + }; }) - -/* - just in case: - the token should not be here. - the token should be in the 1st line of the process.env file instead. -*/ -client.login(process.env.TOKEN); // Log the bot in From 4d86251bff04d07cf520e2702d99a0d116d20da9 Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 14:42:13 +0200 Subject: [PATCH 02/10] Update README.md --- README.md | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 37316af..958ed4a 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,12 @@ -# Discord.JS 12.4.1 Modmail +# Discord.JS 13 Modmail -A modmail with rich features. +A modmail with rich features using the latest discord.js version. -## Links - -- Read more about the features [here](https://github.com/Cyanic76/discord-modmail/wiki/Features). -- Here's how to get the modmail [up and running](https://github.com/Cyanic76/discord-modmail/wiki/Installation) - - [Needed npm modules](https://github.com/Cyanic76/discord-modmail/wiki/Dependencies) -- [Want to contribute?](https://github.com/Cyanic76/discord-modmail/wiki/Contributing) - -## discord.js 13 update +:warning: There is currently **NO SUPPORT** for this branch. Use at your own risk! [Roadmap](https://github.com/Cyanic76/discord-modmail/pull/33) -This project **will** get updated to discord.js 13 at the same time as [my server's bot](https://github.com/Cyanic76/Dave.js). - -No slash command will be used for now, but they will come in a future update. +## Links -Use [Discord's Threads](https://support.discord.com/hc/en-us/articles/4403205878423-Threads) for now. +Coming soon. [Read here for djs 12](https://github.com/Cyanic76/discord-modmail#links) --- From 50c0609838f1d2a25bb80b81598317d69a26585d Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 14:43:43 +0200 Subject: [PATCH 03/10] Update djs version --- package.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 41a8492..afce1c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord-modmail", - "version": "1.0.0", + "version": "1.1.0", "description": "JavaScript modmail bot with rich features.", "main": "bot.js", "scripts": { @@ -8,13 +8,12 @@ }, "dependencies": { "express": "^4.17.1", - "discord.js": "^12.4.1", + "discord.js": "^13.1.0", "quick.db": "^7.1.2", - "ubuntu-pastebin": "^1.0.1", - "@replit/database": "^2.0.1" + "ubuntu-pastebin": "^1.0.1" }, "engines": { - "node": "12.x" + "node": "16.x" }, "repository": { "url": "https://github.com/Cyanic76/discord-modmail" From 2a58f15a4c88f522bc37e6e8d6fe7e41095142f7 Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 14:44:48 +0200 Subject: [PATCH 04/10] No support for replit yet --- replit.js | 270 ------------------------------------------------------ 1 file changed, 270 deletions(-) delete mode 100644 replit.js diff --git a/replit.js b/replit.js deleted file mode 100644 index c8384c6..0000000 --- a/replit.js +++ /dev/null @@ -1,270 +0,0 @@ -/* - this file is optimized for repl.it. -*/ - -const Database = require("@replit/database"); -const Discord = require("discord.js"); -const db = new Database(); -const config = require("./config.json"); - -// declare the client -const client = new Discord.Client(); - -// do something when the bot is logged in -client.on("ready", () => { - console.log(`Successfully logged in as ${client.user.tag}.`) - console.log(`Guild ID: ${config.guild}\nLogs channel ID: ${config.log}\nPrefix: ${config.prefix}`) -}) - -client.on("message", async message => { - - if(message.channel.type === "dm"){ - if(message.author.bot) return; - if(message.content.includes("@everyone") || message.content.includes("@here")) return message.author.send("I'm sorry, but you can not use everyone/here mentions in a modmail thread.") - let active = await db.get(`support_${message.author.id}`) - let guild = client.guilds.cache.get(config.guild); - let channel, found = true; - let user = await db.get(`isBlocked${message.author.id}`); - if(user === true || user === "true") return message.react("❌"); - if(active === null){ - active = {}; - let everyone = guild.roles.cache.get(guild.roles.everyone.id); - let bot = guild.roles.cache.get(config.roles.bot); - let ctno = await db.get("ticket"); // 1 for example - await db.set("ticket", ctno+1); - let actualticket = await db.get("ticket"); - channel = await guild.channels.create(`${message.author.username}-${message.author.discriminator}`, { type: 'text', reason: `New modmail thread: #${actualticket}.` }); - channel.setParent(config.ticketCategory); - channel.setTopic(`#${actualticket} | Use ${config.prefix}complete to close this ticket | ${message.author.username}'s ticket`) - config.roles.mod.forEach(mod => { - let modrole = guild.roles.cache.get(mod); - if(!modrole){ - console.warn("I could not fetch this role. Does it exist? Is this the right role ID?") - } else { - channel.createOverwrite(modrole, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - READ_MESSAGE_HISTORY: true - }); - } - }) - channel.createOverwrite(everyone, { - VIEW_CHANNEL: false - }); - channel.createOverwrite(bot, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - READ_MESSAGE_HISTORY: true, - MANAGE_MESSAGES: true - }) - let author = message.author; - const newTicket = new Discord.MessageEmbed() - .setColor("GREEN") - .setAuthor(author.tag, author.avatarURL({dynamic: true})) - .setTitle(`Ticket #${actualticket}`) - .addField("Channel", `<#${channel.id}>`, true) - let supportServer = client.guilds.cache.get(config.guild); - // Make sure the channels get registered to the bot's cache - supportServer.channels.cache.get(config.log); - supportServer.channels.cache.get(channel.id); - if(config.logs){ - try { - supportServer.channels.cache.get(config.log).send({embed: newTicket}) - } catch(e) { - if(e) supportServer.channels.cache.get(config.log).send(`Ticket #${actualticket} was created by ${author.tag}.`) - } - } - try { - client.channels.cache.get(channel.id).send(`This ticket was created by ${author.tag}.`); - } catch(e) { - supportServer.channels.cache.get(channel.id).send(`This ticket was created by ${author.tag}.`) - } - message.author.send(`Thanks for contacting the support team! We'll get back to you quickly.\nYour ticket ID is #${actualticket}.`) - active.channelID = channel.id; - active.targetID = author.id; - } - channel = client.channels.cache.get(active.channelID); - var msg = message.content; - var isPaused = await db.get(`suspended${message.author.id}`); - var isBlocked = await db.get(`isBlocked${message.author.id}`); - if(isPaused === true){ - return message.channel.send("Sorry, but your ticket is currently paused. I'll message you back when the support team unpause it.") - } - if(isBlocked === true) return; // the user is blocked, so we're just gonna move on. - if(message.attachments.size > 0){ - let attachment = new Discord.MessageAttachment(message.attachments.first().url) - try { - client.channels.cache.get(active.channelID).send(`${message.author.username} > ${msg}`, {files: [message.attachments.first().url]}) - } catch(e) { - if(e) client.guilds.cache.get(config.guild).channels.cache.get(active.channelID).send(`${message.author.username} > ${msg}`, {files: [message.attachments.first().url]}) - } - } else { - try { - client.channels.cache.get(active.channelID).send(`${message.author.username} > ${msg}`); - } catch(e) { - if(e) client.guilds.cache.get(config.guild).channels.cache.get(active.channelID).send(`${message.author.username} > ${msg}`) - } - } - await db.set(`support_${message.author.id}`, active); - await db.set(`supportChannel_${active.channelID}`, message.author.id); - return; - } - if(message.author.bot) return; - var support = await db.get(`supportChannel_${message.channel.id}`); - let supportServer = client.guilds.cache.get(config.guild); - if(support){ - var support = await db.get(`support_${support}`); - let supportUser = client.users.cache.get(support.targetID); - if(!supportUser) return message.channel.delete(); - - // reply (with user and role) - if(message.content.startsWith(`${config.prefix}reply`)){ - var isPause = await db.get(`suspended${support.targetID}`); - let isBlock = await db.get(`isBlocked${support.targetID}`); - if(isPause === true) return message.channel.send("This ticket already paused. Unpause it to continue.") - if(isBlock === true) return message.channel.send("The user is blocked. Unblock them to continue or close the ticket.") - var args = message.content.split(" ").slice(1) - let msg = args.join(" "); - message.react("✅"); - if(message.attachments.size > 0){ - let attachment = new Discord.MessageAttachment(message.attachments.first().url) - return supportUser.send(`${message.author.username} > ${msg}`, {files: [message.attachments.first().url]}) - } else { - return supportUser.send(`${message.author.username} > ${msg}`); - } - }; - - // anonymous reply - if(message.content.startsWith(`${config.prefix}areply`)){ - var isPause = await db.get(`suspended${support.targetID}`); - let isBlock = await db.get(`isBlocked${support.targetID}`); - if(isPause === true) return message.channel.send("This ticket already paused. Unpause it to continue.") - if(isBlock === true) return message.channel.send("The user is blocked. Unblock them to continue or close the ticket.") - var args = message.content.split(" ").slice(1) - let msg = args.join(" "); - message.react("✅"); - return supportUser.send(`Support Team > ${msg}`); - }; - - // print user ID - if(message.content === `${config.prefix}id`){ - return message.channel.send(`User's ID is **${support.targetID}**.`); - }; - - // suspend a thread - if(message.content === `${config.prefix}pause`){ - var isPause = await db.get(`suspended${support.targetID}`); - if(isPause === true || isPause === "true") return message.channel.send("This ticket already paused. Unpause it to continue.") - await db.set(`suspended${support.targetID}`, true); - var suspend = new Discord.MessageEmbed() - .setDescription(`⏸️ This thread has been **locked** and **suspended**. Do \`${config.prefix}continue\` to cancel.`) - .setTimestamp() - .setColor("YELLOW") - message.channel.send({embed: suspend}); - return client.users.cache.get(support.targetID).send("Your ticket has been paused. We'll send you a message when we're ready to continue.") - }; - - // continue a thread - if(message.content === `${config.prefix}continue`){ - var isPause = await db.get(`suspended${support.targetID}`); - if(isPause === null || isPause === false) return message.channel.send("This ticket was not paused."); - await db.delete(`suspended${support.targetID}`); - var c = new Discord.MessageEmbed() - .setDescription("▶️ This thread has been **unlocked**.") - .setColor("BLUE").setTimestamp() - message.channel.send({embed: c}); - return client.users.cache.get(support.targetID).send("Hi! Your ticket isn't paused anymore. We're ready to continue!"); - } - - // block a user - if(message.content.startsWith(`${config.prefix}block`)){ - var args = message.content.split(" ").slice(1) - let reason = args.join(" "); - if(!reason) reason = `Unspecified.` - let user = client.users.fetch(`${support.targetID}`); // djs want a string here - const blocked = new Discord.MessageEmbed() - .setColor("RED").setAuthor(user.tag) - .setTitle("User blocked") - .addField("Channel", `<#${message.channel.id}>`, true) - .addField("Reason", reason, true) - if(config.logs){ - client.channels.cache.get(config.log).send({embed: blocked}) - } - let isBlock = await db.get(`isBlocked${support.targetID}`); - if(isBlock === true) return message.channel.send("The user is already blocked.") - await table.set(`isBlocked${support.targetID}`, true); - var c = new Discord.MessageEmbed() - .setDescription("⏸️ The user has been blocked from the modmail. You may now close the ticket or unblock them to continue.") - .setColor("RED").setTimestamp() - message.channel.send({embed: c}); - return; - } - - // complete - if(message.content.toLowerCase() === `${config.prefix}complete`){ - var embed = new Discord.MessageEmbed() - .setDescription(`This ticket will be deleted in **10** seconds...\n:lock: This thread has been locked and closed.`) - .setColor("RED").setTimestamp() - message.channel.send({embed: embed}) - var timeout = 10000 - setTimeout(() => {end(support.targetID);}, timeout) - } - async function end(userID){ - let actualticket = await db.get("ticket"); - message.channel.delete() - let u = await client.users.fetch(userID); - let end_log = new Discord.MessageEmbed() - .setColor("RED").setAuthor(u.tag, u.avatarURL()) - .setDescription(`Ticket #${actualticket} closed.\nUser: ${u.username}\nID: ${userID}`) - .setTimestamp() - await db.delete(`support_${userID}`); - supportServer.channels.cache.get(config.log).send({embed:end_log}); - return client.users.cache.get(support.targetID).send(`Thanks for getting in touch with us. If you wish to open a new ticket, feel free to message me.\nYour ticket #${actualticket} has been closed.`) - } - }; -}) - -client.on("message", async message => { - if(message.content.startsWith(`${config.prefix}unblock`)){ - if(message.guild.member(message.author).roles.cache.has(config.roles.mod)){ - var args = message.content.split(" ").slice(1); - client.users.fetch(`${args[0]}`).then(async user => { - let data = await table.get(`isBlocked${args[0]}`); - if(data === true){ - await db.delete(`isBlocked${args[0]}`); - return message.channel.send(`Successfully unblocked ${user.username} (${user.id}) from the modmail service.`); - } else { - return message.channel.send(`${user.username} (${user.id}) is not blocked from the modmail at the moment.`) - } - }).catch(err => { - if(err) return message.channel.send("Unknown user."); - }) - } else { - return message.channel.send("You can not use that."); - } - } -}) - -client.on("guildMemberRemove", async member => { - if(config.deleteTicketOnLeave === true){ - let active = await db.get(`support_${message.author.id}`); - if(active === null) return; - client.channels.cache.get(active.channelID).delete(); - await db.delete(`support_${message.author.id}`); - let end_log = new Discord.MessageEmbed() - .setColor("RED").setAuthor(member.tag, member.avatarURL()) - .setDescription(`Ticket #${actualticket} closed because the user has left the server.\nUser: ${member.username}\nID: ${member.id}`) - .setTimestamp() - supportServer.channels.cache.get(config.log).send({embed:end_log}); - return; - } else return; -}) - - -/* - just in case: - the token should not be here. - the token should be in the 1st line of the process.env file instead. - if you still want your token here, replace process.env.TOKEN with "YOUR TOKEN". -*/ -client.login(process.env['TOKEN']); // Log the bot in From b540dcf1f6f02eadc479b14a0280b01f60f7b07c Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 14:47:04 +0200 Subject: [PATCH 05/10] Updated --- bot.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bot.js b/bot.js index 4ed4164..ac7e83b 100644 --- a/bot.js +++ b/bot.js @@ -24,15 +24,15 @@ client.login(config.token.bot); client.on("messageCreate", async message => { if(message.author.bot) return; if(message.content.includes("@everyone") || message.content.includes("@here")) return message.author.send({content: "You're not allowed to use those mentions."}); - console.log("01 no mention, not a bot"); // Used a new table so it doesn't get messed up with the old one const table = new db.table("Support13"); if(message.channel.type === "DM"){ let active = await table.get(`support_${message.author.id}`); let block = await table.get(`blocked_${message.author.id}`); + if(config.dmUsers === false) return message.author.send("Hey! Sorry, but the modmail is currently closed.") if(block === true) return message.author.send("You are not allowed to use modmail."); - let guild = await client.guilds.fetch(''); // set the server id here - let tc = await guild.channels.fetch(''); // set the category id for your tickets here + let guild = await client.guilds.fetch(config.guild); + let tc = await guild.channels.fetch(config.ticketCategory); let channel, found = true; if(active === null){ await table.add("Tickets", 1); @@ -49,7 +49,7 @@ client.on("messageCreate", async message => { .setDescription(`opened ticket #${ticket}.`) .setTimestamp() .setColor("0x6666ff") - let logs = await client.channels.fetch(''); // set the log channel id here + let logs = await client.channels.fetch(config.log); // set the log channel id here logs.send({embeds: [newTicketLog]}); message.author.send(`Hello! Thanks for getting in touch. Our support team will get back to you quickly.`); await table.set(`support_${author.id}`, {channel: channel.id, target: message.author.id, ticket: ticket}); @@ -78,16 +78,16 @@ client.on("messageCreate", async message => { await user.send(`${message.author.username}: ${pending}`); return; }; - if(message.content === `-id`){ + if(message.content === `${config.prefix}id`){ return message.channel.send({content: `Ticket owner's ID is **${activechannel.author}**.`}); } - if(message.content === `-b` || message.content === `-block`){ + if(message.content === `${config.prefix}b` || message.content === `${config.prefix}block`){ await table.set(`blocked_${activechannel.author}`, true); await user.send(`Hi! You can not use modmail anymore.\nOn top of that, you can't contribute or get in touch via any way from now on.`) message.channel.send(`This user has been blocked from modmail, and other forms of contribution.`); return; }; - if(message.content === `-c` || message.content === `-complete`){ + if(message.content === `${config.prefix}c` || message.content === `${config.prefix}complete`){ await table.delete(`channel_${message.channel.id}`); await table.delete(`support_${activechannel.author}`); await user.send({content: "Hi! Your ticket has been closed.\n\nFeel free to DM me whenever it is needed."}) From 4cffbfab2b8556d3d112e9d902a222c156999fd3 Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:21:46 +0200 Subject: [PATCH 06/10] Set permissions overwrite --- bot.js | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/bot.js b/bot.js index ac7e83b..f6bca74 100644 --- a/bot.js +++ b/bot.js @@ -1,4 +1,4 @@ -const { Client, Intents } = require("discord.js"); +const { Client, Intents, Permissions, MessageEmbed } = require("discord.js"); const client = new Client({ intents: [ Intents.FLAGS.GUILDS, @@ -41,7 +41,24 @@ client.on("messageCreate", async message => { type: "GUILD_TEXT", topic: `#${ticket} | From ${message.author.username}`, parent: tc, - reason: `${message.author.id} opened a ticket through the modmail service.` + reason: `${message.author.id} opened a ticket through the modmail service.`, + permissionOverwrites: [ + {id: guild.roles.everyone, deny: [Permissions.FLAGS.VIEW_CHANNEL]}, + {id: guild.roles.fetch(config.roles.mod), allow: [ + Permissions.FLAGS.VIEW_CHANNEL, + Permissions.FLAGS.SEND_MESSAGES, + Permissions.FLAGS.ATTACH_FILES, + Permissions.FLAGS.EMBED_LINKS, + Permissions.FLAGS.READ_MESSAGE_HISTORY + ]}, + {id: guild.roles.fetch(config.roles.bot), allow: [ + Permissions.FLAGS.VIEW_CHANNEL, + Permissions.FLAGS.SEND_MESSAGES, + Permissions.FLAGS.ATTACH_FILES, + Permissions.FLAGS.EMBED_LINKS, + Permissions.FLAGS.READ_MESSAGE_HISTORY + ]} + ] }); let author = message.author; const newTicketLog = new MessageEmbed() From 937dbede6ee99fd266b6c6df6e13a4417c97cb43 Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:24:02 +0200 Subject: [PATCH 07/10] Update bot.js --- bot.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/bot.js b/bot.js index f6bca74..a6bbfae 100644 --- a/bot.js +++ b/bot.js @@ -13,6 +13,7 @@ const client = new Client({ const { REST } = require("@discordjs/rest"); const { Routes } = require("discord-api-types/v9"); const config = require("./config.json"); +const { paste } = require("ubuntu-pastebin"); const db = require("quick.db"); client.once('ready', async () => { @@ -105,9 +106,21 @@ client.on("messageCreate", async message => { return; }; if(message.content === `${config.prefix}c` || message.content === `${config.prefix}complete`){ + let text = `Ticket #${activeuser.ticket}\n\nAuthor: ${user.username}#${user.discriminator} (${user.id})\n\n`; + let mmap = message.channel.messages.cache.map(m => { + text += `From ${m.author.username} - ID: ${m.id}\n${m.content}\n\n` + }); + paste(text).then(url => { + const newTicketLog = new MessageEmbed() + .setAuthor(user.tag, user.avatarURL()) + .setDescription(`closed ticket #${activeuser.ticket}.\n[Thread](${url})`) + .setTimestamp() + .setColor("0x666666") + .setFooter(`Author ID: ${user.id}`) + await client.channels.fetch(config.log).send({embeds: [newTicketLog]}); + await user.send({content: `Thanks for getting in touch! If you wish to open a new ticket, feel free to DM me.\n\nHere's the link to the thread: ${url}`}) + }); await table.delete(`channel_${message.channel.id}`); await table.delete(`support_${activechannel.author}`); - await user.send({content: "Hi! Your ticket has been closed.\n\nFeel free to DM me whenever it is needed."}) - message.channel.delete(); }; }) From 3053b9fd892944f3ae009405956357243a4221bd Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:26:44 +0200 Subject: [PATCH 08/10] Using process.env.TOKEN --- bot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot.js b/bot.js index a6bbfae..c7fe0bc 100644 --- a/bot.js +++ b/bot.js @@ -20,7 +20,7 @@ client.once('ready', async () => { console.log(`Logged in as ${client.user.tag}`); }) -client.login(config.token.bot); +client.login(process.env.TOKEN); // if it can't, replace process.env.TOKEN with "TOKEN" client.on("messageCreate", async message => { if(message.author.bot) return; From 033b2ef2a2bd2bc9718ff9edadc194f5715d51fa Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:40:34 +0200 Subject: [PATCH 09/10] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 958ed4a..0b05db9 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ A modmail with rich features using the latest discord.js version. -:warning: There is currently **NO SUPPORT** for this branch. Use at your own risk! [Roadmap](https://github.com/Cyanic76/discord-modmail/pull/33) - ## Links -Coming soon. [Read here for djs 12](https://github.com/Cyanic76/discord-modmail#links) +- [Get the modmail up & running](https://github.com/Cyanic76/discord-modmail/wiki/Installation) +- [Host the modmail on repl.it](https://github.com/Cyanic76/discord-modmail/wiki/Installation#replit-users) +- [Errors & fixes](https://github.com/Cyanic76/discord-modmail/wiki/Errors) --- From 6e1f5d78659a3163de37c702c154b1d99c09a8b3 Mon Sep 17 00:00:00 2001 From: Cyanic76 <47304192+Cyanic76@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:42:49 +0200 Subject: [PATCH 10/10] Final commit? --- bot.js | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/bot.js b/bot.js index c7fe0bc..ca2ae95 100644 --- a/bot.js +++ b/bot.js @@ -30,8 +30,10 @@ client.on("messageCreate", async message => { if(message.channel.type === "DM"){ let active = await table.get(`support_${message.author.id}`); let block = await table.get(`blocked_${message.author.id}`); + let hold = await table.get(`hold_${message.author.id}`); if(config.dmUsers === false) return message.author.send("Hey! Sorry, but the modmail is currently closed.") if(block === true) return message.author.send("You are not allowed to use modmail."); + if(hold === true) return message.author.send("The support team put your ticket on hold. Please wait until they get back to you.") let guild = await client.guilds.fetch(config.guild); let tc = await guild.channels.fetch(config.ticketCategory); let channel, found = true; @@ -91,6 +93,7 @@ client.on("messageCreate", async message => { let args = text.split(" ").slice(1); let pending = args.join(" "); let blocked = await table.get(`blocked_${activechannel.author}`); + let onHold = await table.get(`hold_${activechannel.author}`); if(message.content.startsWith(`-r`) || message.content.startsWith(`-reply`)){ if(blocked === true) return message.channel.send({content: "This user is blocked."}); await user.send(`${message.author.username}: ${pending}`); @@ -98,10 +101,26 @@ client.on("messageCreate", async message => { }; if(message.content === `${config.prefix}id`){ return message.channel.send({content: `Ticket owner's ID is **${activechannel.author}**.`}); + }; + if(message.content === `${config.prefix}p` || message.content === `${config.prefix}hold`){ + if(blocked === true) return message.channel.send({content: "This user is blocked."}); + if(onHold === true) return message.channel.send({content: "This thread is already on hold."}); + await table.set(`hold_${activechannel.author}`, true); + message.channel.send(`This thread has been put on hold.`); + await user.send(`Hi! Your ticket has been put on hold.`); + return; } + if(message.content === `${config.prefix}up` || message.content === `${config.prefix}unhold`){ + if(blocked === true) return message.channel.send({content: "This user is blocked."}); + if(onHold === true) return message.channel.send({content: "This thread is not on hold."}); + await table.delete(`hold_${activechannel.author}`); + message.channel.send(`This thread isn't on hold anymore.`); + await user.send(`Hi! Your ticket isn't on hold anymore.`); + return; + } if(message.content === `${config.prefix}b` || message.content === `${config.prefix}block`){ await table.set(`blocked_${activechannel.author}`, true); - await user.send(`Hi! You can not use modmail anymore.\nOn top of that, you can't contribute or get in touch via any way from now on.`) + await user.send(`You can not use modmail until further notice.`) message.channel.send(`This user has been blocked from modmail, and other forms of contribution.`); return; }; @@ -124,3 +143,25 @@ client.on("messageCreate", async message => { await table.delete(`support_${activechannel.author}`); }; }) + +client.on("messageCreate", async message => { + if(message.content.startsWith(`${config.prefix}unblock`)){ + if(message.guild.member(message.author).roles.cache.has(config.roles.mod)){ + var args = message.content.split(" ").slice(1); + client.users.fetch(`${args[0]}`).then(async user => { + const dbTable3 = new db.table("Support13"); + let data = await dbTable3.get(`blocked_${args[0]}`); + if(data === true){ + await dbTable3.delete(`blocked_${args[0]}`); + return message.channel.send(`Successfully unblocked ${user.username} (${user.id}) from the modmail service.`); + } else { + return message.channel.send(`${user.username} (${user.id}) is not blocked from the modmail at the moment.`) + } + }).catch(err => { + if(err) return message.channel.send("Unknown user."); + }) + } else { + return message.channel.send("You can not use that."); + } + } +})