diff --git a/package-lock.json b/package-lock.json index 711d7f5..aaf206b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "modmailbot", - "version": "2.30.1", + "version": "2.31.0-beta.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -43,9 +43,9 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "acorn": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", - "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", "dev": true }, "acorn-jsx": { @@ -171,11 +171,6 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -792,13 +787,13 @@ } }, "eris": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/eris/-/eris-0.11.1.tgz", - "integrity": "sha512-Ct32iXjESOnmklxZCEA281BQsTlAsS9xzQkbGlnvzXshCjBptWJ5h8Oxbu67ui1DirsYs0WipB8EBC9ITQ5ZQA==", + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/eris/-/eris-0.13.2.tgz", + "integrity": "sha512-/MAio73lCpgzREqMlrk3UhKt7bBc1VRPnotCnqzTaicHxIYhg3Ghh6jzT1hB36wDcdPCLx6UMzzcDFpxLZtuzA==", "requires": { - "opusscript": "^0.0.4", - "tweetnacl": "^1.0.0", - "ws": "^7.1.2" + "opusscript": "^0.0.7", + "tweetnacl": "^1.0.1", + "ws": "^7.2.1" } }, "escape-string-regexp": { @@ -1929,9 +1924,9 @@ }, "dependencies": { "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } }, @@ -1944,9 +1939,9 @@ } }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, "knex": { "version": "0.20.3", @@ -2135,9 +2130,9 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "minipass": { "version": "2.9.0", @@ -2183,11 +2178,11 @@ } }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "moment": { @@ -2527,9 +2522,9 @@ } }, "opusscript": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/opusscript/-/opusscript-0.0.4.tgz", - "integrity": "sha512-bEPZFE2lhUJYQD5yfTFO4RhbRZ937x6hRwBC1YoGacT35bwDVwKFP1+amU8NYfZL/v4EU7ZTU3INTqzYAnuP7Q==", + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/opusscript/-/opusscript-0.0.7.tgz", + "integrity": "sha512-DcBadTdYTUuH9zQtepsLjQn4Ll6rs3dmeFvN+SD0ThPnxRBRm/WC1zXWPg+wgAJimB784gdZvUMA57gDP7FdVg==", "optional": true }, "os-homedir": { @@ -2787,9 +2782,9 @@ }, "dependencies": { "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } }, @@ -3519,9 +3514,9 @@ "dev": true }, "tweetnacl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz", - "integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", "optional": true }, "type-check": { @@ -3816,12 +3811,9 @@ } }, "ws": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz", - "integrity": "sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg==", - "requires": { - "async-limiter": "^1.0.0" - } + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", + "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==" }, "xdg-basedir": { "version": "3.0.0", @@ -3894,9 +3886,9 @@ } }, "yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-xLTUnCMc4JhxrPEPUYD5IBR1mWCK/aT6+RJ/K29JY2y1vD+FhtgKK0AXRWvI262q3QSffAQuTouFIKUuHX89wQ==", + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", + "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" diff --git a/package.json b/package.json index d888756..39c0118 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "url": "https://github.com/Dragory/modmailbot" }, "dependencies": { - "eris": "^0.11.1", + "eris": "^0.13.2", "humanize-duration": "^3.12.1", "ini": "^1.3.5", "json5": "^2.1.1", diff --git a/src/config.js b/src/config.js index 5d649f8..a9bf76a 100644 --- a/src/config.js +++ b/src/config.js @@ -62,6 +62,7 @@ const defaultConfig = { "mailGuildId": null, "mainGuildId": null, "logChannelId": null, + "errorChannelId": null, "prefix": "!", "snippetPrefix": "!!", @@ -144,7 +145,7 @@ for (const [key, value] of Object.entries(process.env)) { loadedEnvValues++; } -if (process.env.PORT && !process.env.MM_PORT) { +if (process.env.PORT && ! process.env.MM_PORT) { // Special case: allow common "PORT" environment variable without prefix userConfig.port = process.env.PORT; loadedEnvValues++; diff --git a/src/index.js b/src/index.js index 3e1615e..010cfc5 100644 --- a/src/index.js +++ b/src/index.js @@ -16,18 +16,6 @@ try { process.exit(1); } -// Error handling -process.on('uncaughtException', err => { - // Unknown message types (nitro boosting messages at the time) should be safe to ignore - if (err && err.message && err.message.startsWith('Unhandled MESSAGE_CREATE type')) { - return; - } - - // For everything else, crash with the error - console.error(err); - process.exit(1); -}); - let testedPackage = ''; try { const packageJson = require('../package.json'); @@ -47,16 +35,19 @@ const main = require('./main'); const knex = require('./knex'); const legacyMigrator = require('./legacy/legacyMigrator'); +// Error handling +process.on('uncaughtException', err => { + console.error(err); + utils.postError(config.errorChannelId, `\`\`\`js\n${err.stack}\n\`\`\``); +}); + // Force crash on unhandled rejections (use something like forever/pm2 to restart) process.on('unhandledRejection', err => { - if (err instanceof utils.BotError || (err && err.code)) { - // We ignore stack traces for BotErrors (the message has enough info) and network errors from Eris (their stack traces are unreadably long) - console.error(`Error: ${err.message}`); - } else { - console.error(err); + if ((err && err.code)) { + // We ignore stack traces for network errors from Eris (their stack traces are unreadably long) + err = new Error(err.message); } - - process.exit(1); + utils.postError(config.errorChannelId, `\`\`\`js\n${err.stack}\n\`\`\``); }); (async function() { diff --git a/src/modules/id.js b/src/modules/id.js index 18fecdf..d7ed1fd 100644 --- a/src/modules/id.js +++ b/src/modules/id.js @@ -3,7 +3,7 @@ module.exports = ({ bot, knex, config, commands }) => { thread.postSystemMessage(thread.user_id); }); - commands.addInboxThreadCommand('dm_channel_id', [], async (msg, args, thread) => { + commands.addInboxThreadCommand('dmid', [], async (msg, args, thread) => { const dmChannel = await thread.getDMChannel(); thread.postSystemMessage(dmChannel.id); }); diff --git a/src/modules/ping.js b/src/modules/ping.js new file mode 100644 index 0000000..64ff25d --- /dev/null +++ b/src/modules/ping.js @@ -0,0 +1,5 @@ +module.exports = ({ commands }) => { + commands.addInboxThreadCommand('ping', '', async (msg) => { + msg.channel.createMessage('Pong!').then((m) => m.edit(`Pong!\nResponse: \`${m.createdAt - msg.createdAt}ms\`\nGateway: \`${msg.channel.guild.shard.latency}ms\``)); + }); +}; diff --git a/src/modules/reply.js b/src/modules/reply.js index bc2afe3..ac6f987 100644 --- a/src/modules/reply.js +++ b/src/modules/reply.js @@ -1,24 +1,11 @@ -const attachments = require("../data/attachments"); const utils = require('../utils'); module.exports = ({ bot, knex, config, commands }) => { // Mods can reply to modmail threads using !r or !reply // These messages get relayed back to the DM thread between the bot and the user - commands.addInboxThreadCommand('reply', '[text$]', async (msg, args, thread) => { - if (! args.text && msg.attachments.length === 0) { - utils.postError(msg.channel, 'Text or attachment required'); - return; - } - - const replied = await thread.replyToUser(msg.member, args.text || '', msg.attachments, false); - if (replied) msg.delete(); - }, { - aliases: ['r'] - }); - // Anonymous replies only show the role, not the username - commands.addInboxThreadCommand('anonreply', '[text$]', async (msg, args, thread) => { + commands.addInboxThreadCommand('reply', '[text$]', async (msg, args, thread) => { if (! args.text && msg.attachments.length === 0) { utils.postError(msg.channel, 'Text or attachment required'); return; @@ -27,6 +14,6 @@ module.exports = ({ bot, knex, config, commands }) => { const replied = await thread.replyToUser(msg.member, args.text || '', msg.attachments, true); if (replied) msg.delete(); }, { - aliases: ['ar'] + aliases: ['r'] }); }; diff --git a/src/modules/snippets.js b/src/modules/snippets.js index e9c1271..d46d58d 100644 --- a/src/modules/snippets.js +++ b/src/modules/snippets.js @@ -33,34 +33,12 @@ module.exports = ({ bot, knex, config, commands }) => { if (msg.author.bot) return; if (! msg.content) return; - if (! msg.content.startsWith(config.snippetPrefix) && ! msg.content.startsWith(config.snippetPrefixAnon)) return; - - let snippetPrefix, isAnonymous; - - if (config.snippetPrefixAnon.length > config.snippetPrefix.length) { - // Anonymous prefix is longer -> check it first - if (msg.content.startsWith(config.snippetPrefixAnon)) { - snippetPrefix = config.snippetPrefixAnon; - isAnonymous = true; - } else { - snippetPrefix = config.snippetPrefix; - isAnonymous = false; - } - } else { - // Regular prefix is longer -> check it first - if (msg.content.startsWith(config.snippetPrefix)) { - snippetPrefix = config.snippetPrefix; - isAnonymous = false; - } else { - snippetPrefix = config.snippetPrefixAnon; - isAnonymous = true; - } - } + if (! msg.content.startsWith(config.snippetPrefixAnon)) return; const thread = await threads.findByChannelId(msg.channel.id); if (! thread) return; - let [, trigger, rawArgs] = msg.content.slice(snippetPrefix.length).match(/(\S+)(?:\s+(.*))?/s); + let [, trigger, rawArgs] = msg.content.slice(config.snippetPrefixAnon.length).match(/(\S+)(?:\s+(.*))?/s); trigger = trigger.toLowerCase(); const snippet = await snippets.get(trigger); @@ -70,7 +48,7 @@ module.exports = ({ bot, knex, config, commands }) => { args = args.map(arg => arg.value); const rendered = renderSnippet(snippet.body, args); - const replied = await thread.replyToUser(msg.member, rendered, [], isAnonymous); + const replied = await thread.replyToUser(msg.member, rendered, [], true); if (replied) msg.delete(); });