├── .eslintrc ├── .gitignore ├── .prettierrc ├── README.md ├── commands ├── annon.js ├── block.js ├── close.js ├── log.js ├── open.js ├── re.js ├── reply.js └── unblock.js ├── config.js ├── database ├── databaseHandler.js └── template.js ├── help.md ├── logs └── placeholder.txt ├── modmail.js ├── modules ├── channelLogging.js └── commandHandler.js ├── package.json ├── replies ├── example.json └── hi.json └── server.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parserOptions": { 4 | "ecmaVersion": 2020 5 | }, 6 | 7 | "env": { 8 | "es6": true 9 | }, 10 | 11 | "rules": { 12 | "no-unused-vars": ["error", { "vars": "all", "args": "after-used", "ignoreRestSiblings": false }] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | package-lock.json 3 | logs/* 4 | config.js 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "semi": true, 4 | "singleQuote": true, 5 | "printWidth": 2500 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ModMail 2 | 3 | Welcome to ModMail. ModMail is an open-source ModMail bot that helps Discord Guild Moderators help their community easily and privately! 4 | 5 | Information: This bot is written in Eris. You'll need to install [node.js](https://nodejs.org/en/) to run it. This bot not hosted anywhere, you will have to host it yourself. For starter users you can use things like [glitch.com](https://glitch.com/). 6 | 7 | # Getting started 8 | 9 | To setup the bot, head over to [Discord's developer portal](https://discord.com/developers/applications), click new application, then bot, and add a bot account. Copy the token and put it into the token slot of the config file. To run, ensure you have all the components installed; 10 | 11 | `npm install eris` 12 | `npm install moment` 13 | `npm install axios` 14 | 15 | ### Configure the bot in config.js 16 | 17 | ``` 18 | token: 'YOUR BOT TOKEN HERE', 19 | databaseToken: 'YOUR MONGODB TOKEN HERE', // We use MongoDB to store data! https://www.mongodb.com/ 20 | 21 | mainGuild: '', // Main ModMail Guild ID (server) 22 | logChannel: '', // Channel ID of where you want ModMail Logs 23 | mailChannel: '', // **Category** ID of where you want ModMail channels to be! 24 | modRoles: [''], 25 | useOverwrites: false, // Set this to true if you'd like to sync the modmail channel with the parent category (This will void mod roles) 26 | 27 | status: 'DM me for support!', // This will be the bot's playing status 28 | color: 0xfcfcfc, // Color of logging embeds 29 | prefix: '!', // Bot prefix for commands 30 | msgPrefix: 'Staff' // The prefix that shows on messages (ex. Staff pink,: Hi!) 31 | channelTopic: 'ModMail Channel' // This is what the channel topic is set to upon creation. 32 | ``` 33 | 34 | A list of all commands can be found [here](https://github.com/asdbee/ModMail/blob/master/help.md) 35 | 36 | **If you're running into any issues with your current ModMail, ensure that all code is updated. If you still encounter an error, post an [issue](https://github.com/asdbee/ModMail/issues)** 37 | 38 | **READ**: This GitHub repository may be used for educational purposes and personal use. The contents of this repository must not be reuploaded unless forked. Reuploading this code and claiming it was created by you or such, may lead to legal implications. 39 | -------------------------------------------------------------------------------- /commands/annon.js: -------------------------------------------------------------------------------- 1 | const config = require('../config.js'); 2 | module.exports = { 3 | name: 'annon', 4 | description: 'Replies to a user in a ModMail thread without your username showing..', 5 | usage: '{prefix}annon [text]', 6 | shortHands: ['ar'], 7 | execute(client, msg, args, checkMail) { 8 | if (checkMail === null) return client.createMessage(msg.channel.id, '`!` There is no ModMail affiliated with this channel.'); 9 | const fullU = msg.author.username + '#' + msg.author.discriminator; 10 | if (args[1] === undefined) return; 11 | const content = msg.content.slice(config.prefix.length + args[0].length + 1); 12 | client 13 | .getDMChannel(checkMail.userID) 14 | .then((client) => client.createMessage('**' + config.msgPrefix + '**: ' + content)) 15 | .then(client.createMessage(msg.channel.id, '(ANNON) **' + fullU + '**: ' + content), msg.delete()); 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /commands/block.js: -------------------------------------------------------------------------------- 1 | const mail = require('../modmail.js').get; 2 | module.exports = { 3 | name: 'block', 4 | description: 'Blocks a user from using ModMail.', 5 | usage: '{prefix}block [id]', 6 | shortHands: [''], 7 | execute(client, msg, args, checkMail) { 8 | if (args[1] === undefined) { 9 | mail.configBan('fromChannel', msg.channel.id, true); 10 | client.createMessage(msg.channel.id, '`✔` Blocked user'); 11 | } else if (args[1] !== undefined) { 12 | mail.configBan('fromUser', args[1].replace(/[\\<>@#&!]/g, ''), true); 13 | client.createMessage(msg.channel.id, '`✔` Blocked user'); 14 | } 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /commands/close.js: -------------------------------------------------------------------------------- 1 | const mail = require('../modmail.js').get; 2 | const config = require('../config.js'); 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | module.exports = { 6 | name: 'close', 7 | description: 'Closes a Modmail thread.', 8 | usage: '{prefix}annon [text]', 9 | shortHands: [''], 10 | execute(client, msg, args, checkMail) { 11 | if (checkMail === null) return client.createMessage(msg.channel.id, '`!` There is no ModMail affiliated with this channel.'); 12 | if (args[1] === undefined) { 13 | mail.updateDB(msg.channel.id, true, false); 14 | client 15 | .getDMChannel(checkMail.userID) 16 | .then((client) => client.createMessage('**ModMail Notification**: Your ModMail has been closed. Reply to create a new one.')) 17 | .then(() => { 18 | client.createMessage(config.logChannel, { 19 | embed: { 20 | title: 'ModMail Closed', 21 | fields: [ 22 | { 23 | name: 'ModMail', 24 | value: msg.channel.name + '\n(`' + msg.channel.id + '`)', 25 | inline: true, 26 | }, 27 | { 28 | name: 'Details', 29 | value: 'Moderator: ' + msg.author.mention + '\n(' + msg.author.username + '#' + msg.author.discriminator + ')', 30 | inline: true, 31 | }, 32 | ], 33 | color: config.color, 34 | }, 35 | }); 36 | try { 37 | const file = path.join(__dirname, '../logs/' + msg.channel.id + '.txt'); 38 | const buffer = fs.readFileSync(file); 39 | client 40 | .createMessage(config.logChannel, `ModMail Transcript (${msg.channel.id})`, { 41 | file: buffer, 42 | name: 'transcript.txt', 43 | }) 44 | .then(msg.channel.delete()); 45 | } catch (error) { 46 | client.createMessage(msg.channel.id, '`X` Unable to close channel due to an error.\n`' + error + '`'); 47 | } 48 | }); 49 | } else if (args[1] === 'silent') { 50 | client.createMessage(config.logChannel, { 51 | embed: { 52 | title: 'ModMail Closed', 53 | fields: [ 54 | { 55 | name: 'ModMail', 56 | value: msg.channel.name + '\n(`' + msg.channel.id + '`)', 57 | inline: true, 58 | }, 59 | { 60 | name: 'Details', 61 | value: 'Moderator: ' + msg.author.mention + '\n(' + msg.author.username + '#' + msg.author.discriminator + ')', 62 | inline: true, 63 | }, 64 | ], 65 | color: config.color, 66 | }, 67 | }); 68 | try { 69 | const file = path.join(__dirname, '../logs/' + msg.channel.id + '.txt'); 70 | const buffer = fs.readFileSync(file); 71 | client 72 | .createMessage(config.logChannel, `ModMail Transcript (${msg.channel.id})`, { 73 | file: buffer, 74 | name: 'transcript.txt', 75 | }) 76 | .then(msg.channel.delete()); 77 | } catch (error) { 78 | client.createMessage(msg.channel.id, '`X` Unable to close channel due to an error.\n`' + error + '`'); 79 | } 80 | } 81 | }, 82 | }; 83 | -------------------------------------------------------------------------------- /commands/log.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | module.exports = { 4 | name: 'log', 5 | description: 'Shows the current channel log.', 6 | usage: '{prefix}log', 7 | shortHands: [''], 8 | execute(client, msg, args, checkMail) { 9 | if (checkMail === null) return client.createMessage(msg.channel.id, '`!` There is no ModMail affiliated with this channel.'); 10 | if (args[0].toLowerCase() === 'log') { 11 | const file = path.join(__dirname, '../logs/' + msg.channel.id + '.txt'); 12 | const buffer = fs.readFileSync(file); 13 | client.createMessage(msg.channel.id, 'Current Channel Log', { 14 | file: buffer, 15 | name: 'transcript.txt', 16 | }); 17 | } 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /commands/open.js: -------------------------------------------------------------------------------- 1 | const mail = require('../modmail.js').get; 2 | const config = require('../config.js'); 3 | const moment = require('moment'); 4 | 5 | function updateDB(id, channel, closed, log) { 6 | const getMail = require('../database/template.js'); 7 | getMail.findById(id).then((data) => { 8 | (data.channelID = channel), (data.isClosed = closed), (data.logFile = log); 9 | data.save(); 10 | }); 11 | } 12 | 13 | module.exports = { 14 | name: 'open', 15 | description: 'Opens a ModMail for a user.', 16 | usage: '{prefix}open user', 17 | shortHands: ['r'], 18 | execute(client, msg, args, checkMail) { 19 | if (args[1] === undefined) return; 20 | const user = args[1].replace(/[\\<>@#&!]/g, ''); 21 | mail.getModMail(user).then((mm) => { 22 | let userObject; 23 | client.getRESTGuildMember(config.mainGuild, user).then(async (userOb) => { 24 | if (userOb === undefined) return client.createMessage(msg.channel.id, "`!` This user isn't in this server!"); 25 | userObject = userOb; 26 | 27 | if (mm !== null) { 28 | if (mm.isClosed === false) return client.createMessage(msg.channel.id, '`!` This user already has a thread open!'); 29 | client.createChannel(config.mainGuild, userObject.username + ' ' + userObject.discriminator, 0).then(async (newMail) => { 30 | await updateDB(userObject.id, newMail.id, false, ''); 31 | await newMail.edit({ parentID: config.mailChannel }); 32 | await newMail.editPermission(config.mainGuild, '0', '1024', 'role', '@everyone view denied.'); 33 | await config.modRoles.forEach((r) => { 34 | newMail.editPermission(r, '52224', '8192', 'role', 'ModRole view allowed.'); 35 | }); 36 | await newMail.editPermission(client.user.id, '52224', '0', 'member', 'ModMail app allowed.'); 37 | await client.createMessage(newMail.id, 'New ModMail\n—————————————————\n**Account Information**\n\nCreation Date: ' + moment(userObject.createdAt).format('lll') + '\nJoined Server: ' + moment(userOb.joinedAt).format('lll') + '\n\n**This thread was opened by ' + msg.author.username + '#' + msg.author.discriminator + '**'); 38 | await client.getDMChannel(userObject.id).then((client) => client.createMessage('`!` A ModMail thread has been opened for you.')); 39 | }); 40 | } else if (mm === null) { 41 | client.createChannel(config.mainGuild, userObject.username + ' ' + userObject.discriminator, 0).then(async (newMail) => { 42 | await mail.createDB(userObject.id, newMail.id, false, false); 43 | await newMail.edit({ parentID: config.mailChannel }); 44 | await newMail.editPermission(config.mainGuild, '0', '1024', 'role', '@everyone view denied.'); 45 | await config.modRoles.forEach((r) => { 46 | newMail.editPermission(r, '52224', '8192', 'role', 'ModRole view allowed.'); 47 | }); 48 | await newMail.editPermission(client.user.id, '52224', '0', 'member', 'ModMail app allowed.'); 49 | await client.createMessage(newMail.id, 'New ModMail\n—————————————————\n**Account Information**\n\nCreation Date: ' + moment(userObject.createdAt).format('lll') + '\nJoined Server: ' + moment(userOb.joinedAt).format('lll') + '\n\n**This thread was opened by ' + msg.author.username + '#' + msg.author.discriminator + '**'); 50 | await client.getDMChannel(userObject.id).then((client) => client.createMessage('`!` A ModMail thread has been opened for you.')); 51 | }); 52 | } 53 | }); 54 | }); 55 | }, 56 | }; 57 | -------------------------------------------------------------------------------- /commands/re.js: -------------------------------------------------------------------------------- 1 | const config = require('../config.js'); 2 | const path = require('path'); 3 | module.exports = { 4 | name: 're', 5 | description: 'Replies with a snippet.', 6 | usage: '{prefix}re [reply name]', 7 | shortHands: [''], 8 | execute(client, msg, args, checkMail) { 9 | if (checkMail === null) return client.createMessage(msg.channel.id, '`!` There is no ModMail affiliated with this channel.'); 10 | 11 | const get = path.join(__dirname, '../replies/' + args[1] + '.json'); 12 | const c = require(get); 13 | const fullU = msg.author.username + '#' + msg.author.discriminator; 14 | if (c.annon === false) { 15 | client 16 | .getDMChannel(checkMail.userID) 17 | .then((client) => client.createMessage(config.msgPrefix + ' **' + fullU + '**: ' + c.reply)) 18 | .then(client.createMessage(msg.channel.id, config.msgPrefix + ' **' + fullU + '**: ' + c.reply), msg.delete()); 19 | } 20 | 21 | if (c.annon === true) { 22 | client 23 | .getDMChannel(checkMail.userID) 24 | .then((client) => client.createMessage('**' + config.msgPrefix + '**: ' + c.reply)) 25 | .then(client.createMessage(msg.channel.id, '(Annon) **' + fullU + '**: ' + c.reply), msg.delete()); 26 | } 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /commands/reply.js: -------------------------------------------------------------------------------- 1 | const config = require('../config.js'); 2 | module.exports = { 3 | name: 'reply', 4 | description: 'Replies to a user in a ModMail thread.', 5 | usage: '{prefix}reply [text]', 6 | shortHands: ['r'], 7 | execute(client, msg, args, checkMail) { 8 | if (checkMail === null) return client.createMessage(msg.channel.id, '`!` There is no ModMail affiliated with this channel.'); 9 | let displayName = ''; 10 | if (msg.member.nick !== null) { 11 | displayName = msg.member.nick; 12 | } else if (msg.member.nick === null) { 13 | displayName = msg.member.username + '#' + msg.member.discriminator; 14 | } 15 | let att = ''; 16 | if (msg.attachments[0] !== undefined) { 17 | att = msg.attachments[0].url; 18 | } else if (msg.attachments[0] === undefined) { 19 | att = ''; 20 | } 21 | if (args[1] === undefined) return; 22 | const content = msg.content.slice(config.prefix.length + args[0].length + 1); 23 | client 24 | .getDMChannel(checkMail.userID) 25 | .then((client) => client.createMessage(config.msgPrefix + ' **' + displayName + '**: ' + content)) 26 | .then(client.createMessage(msg.channel.id, config.msgPrefix + ' **' + displayName + '**: ' + content + '\n' + att), msg.delete()); 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /commands/unblock.js: -------------------------------------------------------------------------------- 1 | const mail = require('../modmail.js').get; 2 | module.exports = { 3 | name: 'unblock', 4 | description: 'Unblocks a user.', 5 | usage: '{prefix}unblock [id]', 6 | shortHands: [''], 7 | execute(client, msg, args, checkMail) { 8 | if (args[1] === undefined) { 9 | mail.configBan('fromChannel', msg.channel.id, false); 10 | client.createMessage(msg.channel.id, '`✔` Unblocked user'); 11 | } else if (args[1] !== undefined) { 12 | mail.configBan('fromUser', args[1].replace(/[\\<>@#&!]/g, ''), false); 13 | client.createMessage(msg.channel.id, '`✔` Unblocked user'); 14 | } 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | token: '', 3 | databaseToken: '', 4 | 5 | mainGuild: '', 6 | logChannel: '', 7 | mailChannel: '', 8 | modRoles: [''], 9 | useOverwrites: false, 10 | 11 | status: 'for dms!', 12 | color: 0xfcfcfc, 13 | prefix: '!', 14 | msgPrefix: 'Staff', 15 | channelTopic: '', 16 | }; 17 | -------------------------------------------------------------------------------- /database/databaseHandler.js: -------------------------------------------------------------------------------- 1 | const config = require('../config.js') 2 | const mongoose = require('mongoose') 3 | mongoose.connect(config.databaseToken, { 4 | useNewUrlParser: true, 5 | useUnifiedTopology: true 6 | }).then(console.log('Database Connected')) 7 | -------------------------------------------------------------------------------- /database/template.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const modMail = mongoose.Schema({ 4 | _id: String, 5 | userID: String, 6 | channelID: String, 7 | logFile: String, 8 | isClosed: Boolean, 9 | isBanned: Boolean 10 | }) 11 | 12 | module.exports = mongoose.model('ModMail', modMail) -------------------------------------------------------------------------------- /help.md: -------------------------------------------------------------------------------- 1 | # Modmail Commands 2 | 3 | ## R | Reply 4 | 5 | Replies to the Modmail thread. 6 | 7 | ## AR | Annon 8 | 9 | Replies to the Modmail thread anonymously. 10 | 11 | ## Close 12 | 13 | Closes and deletes the Modmail thread. 14 | 15 | #### Arguments 16 | 17 | Silent: Won't send the user a DM that the thread was closed. 18 | 19 | ## Re 20 | 21 | Replies with a set response. Responses are located in [this folder](https://github.com/asdbee/ModMail/tree/master/replies) 22 | 23 | ## Block 24 | 25 | Blocks or bans a user from using the Modmail bot. They can still DM the bot, but it will not create new threads. 26 | 27 | ## Unblock 28 | 29 | Unblocks or unbans a user, this will allow them to create new threads! 30 | 31 | ## Log 32 | 33 | Sends the current log file of the thread 34 | 35 | ## Open 36 | 37 | Opens a ModMail thread for a user 38 | 39 | **Suggest new commands [here](https://github.com/asdbee/ModMail/issues)** 40 | -------------------------------------------------------------------------------- /logs/placeholder.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asdbee/ModMail/691c0ca1617fdde4bdeb41a6ad3c38de9f7e0439/logs/placeholder.txt -------------------------------------------------------------------------------- /modmail.js: -------------------------------------------------------------------------------- 1 | let get = {}; 2 | 3 | get.updateDB = (channel, closed, log) => { 4 | const getMail = require('./database/template.js'); 5 | getMail.findOne({ channelID: channel }).then((data) => { 6 | (data.channelID = channel), (data.isClosed = closed), (data.logFile = log); 7 | data.save(); 8 | }); 9 | }; 10 | 11 | get.configBan = (where, id, banned) => { 12 | const getMail = require('./database/template.js'); 13 | if (where === 'fromChannel') { 14 | getMail.findOne({ channelID: id }).then((data) => { 15 | data.isBanned = banned; 16 | data.save(); 17 | }); 18 | } else if (where === 'fromUser') { 19 | getMail.findOne({ userID: id }).then((data) => { 20 | data.isBanned = banned; 21 | data.save(); 22 | }); 23 | } 24 | }; 25 | 26 | get.getChannel = (cid) => { 27 | const getMail = require('./database/template.js'); 28 | return getMail.findOne({ channelID: cid }); 29 | }; 30 | 31 | get.getModMail = (id) => { 32 | const getMail = require('./database/template.js'); 33 | return getMail.findById(id); 34 | }; 35 | 36 | get.createDB = (user, channel, closed, logFile, banned) => { 37 | const createMail = require('./database/template.js'); 38 | const newMail = new createMail({ 39 | _id: user, 40 | userID: user, 41 | channelID: channel, 42 | logFile: logFile, 43 | isClosed: closed, 44 | isBanned: banned, 45 | }); 46 | newMail.save(); 47 | }; 48 | 49 | module.exports = { get }; 50 | -------------------------------------------------------------------------------- /modules/channelLogging.js: -------------------------------------------------------------------------------- 1 | const mail = require('../database/template.js'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | module.exports = (client) => { 5 | function updateLog(channel, author, message) { 6 | fs.appendFile(path.join(__dirname, '../logs/' + channel + '.txt'), `${author.username}#${author.discriminator}: ${message}\n`, function (err) { 7 | if (err) { 8 | console.error(`UNABLE TO LOG TO TRANSCRIPT\n${err}`); 9 | } else return; 10 | }); 11 | } 12 | 13 | client.on('messageCreate', (msg) => { 14 | mail.findOne({ channelID: msg.channel.id }).then((data) => { 15 | if (data === null) return; 16 | updateLog(msg.channel.id, msg.author, msg.content); 17 | }); 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /modules/commandHandler.js: -------------------------------------------------------------------------------- 1 | const Eris = require('eris'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const config = require('../config.js'); 5 | const mail = require('../modmail.js').get; 6 | 7 | function getModMail(id) { 8 | const getMail = require('../database/template.js'); 9 | return getMail.findById(id); 10 | } 11 | 12 | module.exports = (client) => { 13 | client.commands = new Eris.Collection(); 14 | 15 | client.on('ready', () => { 16 | const commandFiles = fs.readdirSync(path.resolve(__dirname, '../commands')).filter((file) => file.endsWith('.js')); 17 | 18 | for (const file of commandFiles) { 19 | const command = require(path.resolve(__dirname, `../commands/${file}`)); 20 | client.commands.set(command.name, command); 21 | command.shortHands.forEach((s) => { 22 | if (s === '') return; 23 | client.commands.set(s, command); 24 | }); 25 | } 26 | }); 27 | client.on('messageCreate', (msg) => { 28 | if (msg.author.client) return; 29 | if (msg.guildID === undefined) return; 30 | if (!client.guilds.get(config.mainGuild).members.get(msg.author.id)) return; 31 | if (!msg.content.startsWith(config.prefix)) return; 32 | mail.getChannel(msg.channel.id).then((checkMail) => { 33 | if (checkMail === null) return client.createMessage(msg.channel.id, '`!` There is no modmail affiliated with this channel.'); 34 | const args = msg.content.slice(config.prefix.length).trim().split(' '); 35 | const cmd = args[0].toLowerCase(); 36 | if (!client.commands.has(cmd)) return; 37 | try { 38 | client.commands.get(cmd).execute(client, msg, args, checkMail); 39 | } catch (error) { 40 | client.createMessage(msg.channel.id, '`X` There was an error executing that command.'); 41 | console.log(error.stack); 42 | } 43 | }); 44 | }); 45 | }; 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "modmail", 3 | "version": "0.0.1", 4 | "main": "server.js", 5 | "scripts": { 6 | "start": "node server.js" 7 | }, 8 | "dependencies": { 9 | "axios": "^0.21.1", 10 | "create-file": "^1.0.1", 11 | "eris": "^0.13.4", 12 | "fs": "0.0.1-security", 13 | "moment": "^2.29.1", 14 | "mongoose": "^5.13.7" 15 | }, 16 | "engines": { 17 | "node": "8.x" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /replies/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "reply": "Hello! How can we help you?", 3 | "annon": false 4 | } -------------------------------------------------------------------------------- /replies/hi.json: -------------------------------------------------------------------------------- 1 | { 2 | "reply": "Hello! How can we help you?", 3 | "annon": false 4 | } -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const Eris = require('eris'); 2 | const moment = require('moment'); 3 | const config = require('./config.js'); 4 | const client = new Eris(config.token, { defaultImageFormat: 'png', getAllUsers: false, restMode: true }); 5 | require('./modules/commandHandler.js')(client); 6 | require('./database/databaseHandler.js'); 7 | require('./modules/channelLogging.js')(client); 8 | 9 | const mail = require('./modmail.js').get; 10 | 11 | function updateDB(id, channel, closed, log) { 12 | const getMail = require('./database/template.js'); 13 | getMail.findById(id).then((data) => { 14 | (data.channelID = channel), (data.isClosed = closed), (data.logFile = log); 15 | data.save(); 16 | }); 17 | } 18 | 19 | function fixClosed(msg, fullU) { 20 | client.createChannel(config.mainGuild, msg.author.username + ' ' + msg.author.discriminator, 0).then(async (newMail) => { 21 | await updateDB(msg.author.id, newMail.id, false, ''); 22 | await newMail.edit({ parentID: config.mailChannel }); 23 | await newMail.editPermission(config.mainGuild, '0', '1024', 'role', '@everyone view denied.'); 24 | if (config.useOverwrites === false) { 25 | await config.modRoles.forEach((r) => { 26 | newMail.editPermission(r, '52224', '8192', 'role', 'ModRole view allowed.'); 27 | }); 28 | } else if (config.useOverwrites === true) { 29 | client.guilds 30 | .get(config.mainGuild) 31 | .channels.get(config.mailChannel) 32 | .permissionOverwrites.forEach((c) => { 33 | newMail.editPermission(c.id, c.allow, c.deny, c.type, 'ModMail Permissions'); 34 | }); 35 | } 36 | await newMail.editPermission(client.user.id, '52224', '0', 'member', 'ModMail app allowed.'); 37 | client.getRESTGuildMember(config.mainGuild, msg.author.id).then(async (userOb) => { 38 | await client.createMessage(newMail.id, 'New ModMail\n—————————————————\n**Account Information**\n\nCreation Date: ' + moment(msg.author.createdAt).format('lll') + '\nJoined Server: ' + moment(userOb.joinedAt).format('lll') + '\n\n**' + fullU + '**: ' + msg.cleanContent + '\n' + att); 39 | await client.getDMChannel(msg.author.id).then((client) => client.createMessage('`✔` Your message has been received. A team member will be with you shortly.')); 40 | }); 41 | }); 42 | } 43 | 44 | client.on('ready', () => { 45 | // This below ensure the client runs smoothly. 46 | if (!client.guilds.get(config.mainGuild)) { 47 | console.error('Main guild must be a valid guild.'), process.exit(); 48 | } 49 | if (!client.guilds.get(config.mainGuild).channels.get(config.logChannel)) { 50 | console.error('Log channel must be in main guild.\nProcess exited with code 1'), process.exit(); 51 | } 52 | if (!client.guilds.get(config.mainGuild).channels.get(config.mailChannel)) { 53 | console.error('Mail channel must be in main guild.\nProcess exited with code 1'), process.exit(); 54 | } 55 | if (client.guilds.get(config.mainGuild).channels.get(config.mailChannel).type !== 4) { 56 | console.error('Mail channel must be a category.\nProcess exited with code 1'), process.exit(); 57 | } 58 | config.modRoles.forEach((r) => { 59 | if (!client.guilds.get(config.mainGuild).roles.get(r)) { 60 | console.error('Mod role must be in main guild. [' + r + ']\nProcess exited with code 1'), process.exit(); 61 | } 62 | }); 63 | if (config.msgPrefix.replace(/ /g, '') === '') { 64 | console.error('Add a staff message prefix!\nProcess exited with code 1'), process.exit(); 65 | } 66 | if (config.prefix.replace(/ /g, '') === '') { 67 | console.error('Add a command prefix!\nProcess exited with code 1'), process.exit(); 68 | } 69 | 70 | console.log('Bot updated successfully (' + moment(client.startTime).format('lll') + ')'); 71 | client.editStatus('online', { name: config.status, type: 3 }); 72 | }); 73 | 74 | client.on('guildCreate', (guild) => { 75 | if (guild.id !== config.mainGuild) { 76 | client.guilds.get(guild.id).leave(); 77 | } 78 | }); 79 | 80 | client.on('channelDelete', (channel) => { 81 | const getMail = require('./database/template.js'); 82 | getMail.findOne({ channelID: channel.id }).then((data) => { 83 | if (data === null) return; 84 | data.isClosed = true; 85 | data.save(); 86 | }); 87 | }); 88 | 89 | client.on('error', (err) => { 90 | console.log(err.stack); 91 | if (err.toString().startsWith('Error: Connection reset by peer') || err.toString().startsWith('Error: 1001:')) return; 92 | }); 93 | 94 | client.on('messageCreate', (msg) => { 95 | if (msg.author.bot) return; 96 | //if (!client.guilds.get(config.mainGuild).members.get(msg.author.id)) return 97 | if (msg.guildID === undefined) { 98 | mail.getModMail(msg.author.id).then((checkMail) => { 99 | // Messaging 100 | 101 | const fullU = msg.author.username + '#' + msg.author.discriminator; 102 | const clientName = client.user.username; // was being weird so, const 103 | 104 | let att = ''; 105 | if (msg.attachments[0] !== undefined) { 106 | att = msg.attachments[0].filename + '\n' + msg.attachments[0].url; 107 | } else if (msg.attachments[0] === undefined) { 108 | att = ''; 109 | } 110 | 111 | if (checkMail === null) { 112 | client.createChannel(config.mainGuild, msg.author.username + ' ' + msg.author.discriminator, 0).then(async (newMail) => { 113 | await mail.createDB(msg.author.id, newMail.id, false, false); 114 | await newMail.edit({ parentID: config.mailChannel }); 115 | await newMail.editPermission(config.mainGuild, '0', '1024', 'role', '@everyone view denied.'); 116 | if (config.useOverwrites === false) { 117 | await config.modRoles.forEach((r) => { 118 | newMail.editPermission(r, '52224', '8192', 'role', 'ModRole view allowed.'); 119 | }); 120 | } else if (config.useOverwrites === true) { 121 | client.guilds 122 | .get(config.mainGuild) 123 | .channels.get(config.mailChannel) 124 | .permissionOverwrites.forEach((c) => { 125 | newMail.editPermission(c.id, c.allow, c.deny, c.type, 'ModMail Permissions'); 126 | }); 127 | } 128 | await newMail.editPermission(client.user.id, '52224', '0', 'member', 'ModMail app allowed.'); 129 | client.getRESTGuildMember(config.mainGuild, msg.author.id).then(async (userOb) => { 130 | await client.createMessage(newMail.id, 'New ModMail\n—————————————————\n**Account Information**\n\nCreation Date: ' + moment(msg.author.createdAt).format('lll') + '\nJoined Server: ' + moment(userOb.joinedAt).format('lll') + '\n\n**' + fullU + '**: ' + msg.cleanContent + '\n' + att); 131 | await client.getDMChannel(msg.author.id).then((client) => client.createMessage('`✔` Your message has been received. A team member will be with you shortly.')); 132 | }); 133 | }); 134 | } else if (checkMail !== null) { 135 | if (checkMail.isBanned === true) return client.getDMChannel(checkMail.userID).then((client) => client.createMessage('**ModMail Notification**: You have been blacklisted from using ' + clientName + '!')); 136 | if (checkMail.isClosed === true) { 137 | client.createChannel(config.mainGuild, msg.author.username + ' ' + msg.author.discriminator, 0).then(async (newMail) => { 138 | await updateDB(msg.author.id, newMail.id, false, ''); 139 | await newMail.edit({ parentID: config.mailChannel }); 140 | await newMail.editPermission(config.mainGuild, '0', '1024', 'role', '@everyone view denied.'); 141 | if (config.useOverwrites === false) { 142 | await config.modRoles.forEach((r) => { 143 | newMail.editPermission(r, '52224', '8192', 'role', 'ModRole view allowed.'); 144 | }); 145 | } else if (config.useOverwrites === true) { 146 | client.guilds 147 | .get(config.mainGuild) 148 | .channels.get(config.mailChannel) 149 | .permissionOverwrites.forEach((c) => { 150 | newMail.editPermission(c.id, c.allow, c.deny, c.type, 'ModMail Permissions'); 151 | }); 152 | } 153 | await newMail.editPermission(client.user.id, '52224', '0', 'member', 'ModMail app allowed.'); 154 | client.getRESTGuildMember(config.mainGuild, msg.author.id).then(async (userOb) => { 155 | await client.createMessage(newMail.id, 'New ModMail\n—————————————————\n**Account Information**\n\nCreation Date: ' + moment(msg.author.createdAt).format('lll') + '\nJoined Server: ' + moment(userOb.joinedAt).format('lll') + '\n\n**' + fullU + '**: ' + msg.cleanContent + '\n' + att); 156 | await client.getDMChannel(msg.author.id).then((client) => client.createMessage('`✔` Your message has been received. A team member will be with you shortly.')); 157 | }); 158 | }); 159 | } else if (checkMail.isClosed === false) { 160 | if (checkMail.isBanned === true) return client.getDMChannel(checkMail.userID).then((client) => client.createMessage('**ModMail Notification**: You have been blacklisted from using ' + clientName + '!')); 161 | if (!client.guilds.get(config.mainGuild).channels.get(checkMail.channelID)) return fixClosed(msg, fullU); 162 | client.createMessage(checkMail.channelID, '**' + fullU + '**: ' + msg.cleanContent + '\n' + att); 163 | } 164 | } 165 | }); 166 | } 167 | }); 168 | 169 | process.on('uncaughtException', (error) => { 170 | console.log(error); 171 | }); 172 | 173 | client.connect(); 174 | --------------------------------------------------------------------------------