Move more code from main.js to individual module files. Rename plugins -> modules. Remove some obsolete comments.

master
Dragory 2018-03-13 07:45:31 +02:00
parent 1431ab8c4e
commit ab3d70008a
13 changed files with 180 additions and 161 deletions

View File

@ -91,7 +91,6 @@ class Thread {
dm_message_id: dmMessage.id dm_message_id: dmMessage.id
}); });
// The string type check is due to a knex bug, see https://github.com/tgriesser/knex/issues/1276
if (this.scheduled_close_at) { if (this.scheduled_close_at) {
await this.cancelScheduledClose(); await this.cancelScheduledClose();
await this.postSystemMessage(`Cancelling scheduled closing of this thread due to new reply`); await this.postSystemMessage(`Cancelling scheduled closing of this thread due to new reply`);
@ -144,7 +143,6 @@ class Thread {
dm_message_id: msg.id dm_message_id: msg.id
}); });
// The string type check is due to a knex bug, see https://github.com/tgriesser/knex/issues/1276
if (this.scheduled_close_at) { if (this.scheduled_close_at) {
await this.cancelScheduledClose(); await this.cancelScheduledClose();
await this.postSystemMessage({ await this.postSystemMessage({

View File

@ -20,6 +20,7 @@ module.exports = {
'thanks', 'thanks',
'ty', 'ty',
'k', 'k',
'kk',
'thank you', 'thank you',
'thanx', 'thanx',
'thnx', 'thnx',

View File

@ -1,33 +1,31 @@
const Eris = require('eris'); const Eris = require('eris');
const moment = require('moment');
const humanizeDuration = require('humanize-duration');
const config = require('./config'); const config = require('./config');
const bot = require('./bot'); const bot = require('./bot');
const Queue = require('./queue'); const Queue = require('./queue');
const utils = require('./utils'); const utils = require('./utils');
const threadUtils = require('./threadUtils');
const blocked = require('./data/blocked'); const blocked = require('./data/blocked');
const threads = require('./data/threads'); const threads = require('./data/threads');
const snippets = require('./plugins/snippets'); const reply = require('./modules/reply');
const logCommands = require('./plugins/logCommands'); const close = require('./modules/close');
const moving = require('./plugins/moving'); const snippets = require('./modules/snippets');
const blocking = require('./plugins/blocking'); const logs = require('./modules/logs');
const suspending = require('./plugins/suspending'); const move = require('./modules/move');
const webserver = require('./plugins/webserver'); const block = require('./modules/block');
const greeting = require('./plugins/greeting'); const suspend = require('./modules/suspend');
const webserver = require('./modules/webserver');
const greeting = require('./modules/greeting');
const typingProxy = require('./modules/typingProxy');
const attachments = require("./data/attachments"); const attachments = require("./data/attachments");
const {ACCIDENTAL_THREAD_MESSAGES} = require('./data/constants'); const {ACCIDENTAL_THREAD_MESSAGES} = require('./data/constants');
const messageQueue = new Queue(); const messageQueue = new Queue();
const addInboxServerCommand = (...args) => threadUtils.addInboxServerCommand(bot, ...args);
const humanizeDelay = (delay, opts = {}) => humanizeDuration(delay, Object.assign({conjunction: ' and '}, opts));
// Once the bot has connected, set the status/"playing" message // Once the bot has connected, set the status/"playing" message
bot.on('ready', () => { bot.on('ready', () => {
bot.editStatus(null, {name: config.status}); bot.editStatus(null, {name: config.status});
console.log('Connected! Now listening to DMs.');
}); });
/** /**
@ -155,160 +153,23 @@ bot.on('messageCreate', async msg => {
}); });
}); });
// Typing proxy: forwarding typing events between the DM and the modmail thread
if(config.typingProxy || config.typingProxyReverse) {
bot.on("typingStart", async (channel, user) => {
// config.typingProxy: forward user typing in a DM to the modmail thread
if (config.typingProxy && (channel instanceof Eris.PrivateChannel)) {
const thread = await threads.findOpenThreadByUserId(user.id);
if (! thread) return;
try {
await bot.sendChannelTyping(thread.channel_id);
} catch (e) {}
}
// config.typingProxyReverse: forward moderator typing in a thread to the DM
else if (config.typingProxyReverse && (channel instanceof Eris.GuildChannel) && ! user.bot) {
const thread = await threads.findByChannelId(channel.id);
if (! thread) return;
const dmChannel = await thread.getDMChannel();
if (! dmChannel) return;
try {
await bot.sendChannelTyping(dmChannel.id);
} catch(e) {}
}
});
}
// Check for threads that are scheduled to be closed and close them
async function applyScheduledCloses() {
const threadsToBeClosed = await threads.getThreadsThatShouldBeClosed();
for (const thread of threadsToBeClosed) {
await thread.close();
const logUrl = await thread.getLogUrl();
utils.postLog(utils.trimAll(`
Modmail thread with ${thread.user_name} (${thread.user_id}) was closed as scheduled by ${thread.scheduled_close_name}
Logs: ${logUrl}
`));
}
}
async function scheduledCloseLoop() {
try {
await applyScheduledCloses();
} catch (e) {
console.error(e);
}
setTimeout(scheduledCloseLoop, 2000);
}
// Auto-close threads if their channel is deleted
bot.on('channelDelete', async (channel) => {
if (! (channel instanceof Eris.TextChannel)) return;
if (channel.guild.id !== utils.getInboxGuild().id) return;
const thread = await threads.findOpenThreadByChannelId(channel.id);
if (! thread) return;
console.log(`[INFO] Auto-closing thread with ${thread.user_name} because the channel was deleted`);
await thread.close(true);
const logUrl = await thread.getLogUrl();
utils.postLog(utils.trimAll(`
Modmail thread with ${thread.user_name} (${thread.user_id}) was closed automatically because the channel was deleted
Logs: ${logUrl}
`));
});
// 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
addInboxServerCommand('reply', async (msg, args, thread) => {
if (! thread) return;
const text = args.join(' ').trim();
if (msg.attachments.length) await attachments.saveAttachmentsInMessage(msg);
await thread.replyToUser(msg.member, text, msg.attachments, false);
msg.delete();
});
bot.registerCommandAlias('r', 'reply');
// Anonymous replies only show the role, not the username
addInboxServerCommand('anonreply', async (msg, args, thread) => {
if (! thread) return;
const text = args.join(' ').trim();
if (msg.attachments.length) await attachments.saveAttachmentsInMessage(msg);
await thread.replyToUser(msg.member, text, msg.attachments, true);
msg.delete();
});
bot.registerCommandAlias('ar', 'anonreply');
// Close a thread. Closing a thread saves a log of the channel's contents and then deletes the channel.
addInboxServerCommand('close', async (msg, args, thread) => {
if (! thread) return;
// Timed close
if (args.length) {
if (args[0] === 'cancel') {
// Cancel timed close
// The string type check is due to a knex bug, see https://github.com/tgriesser/knex/issues/1276git
if (thread.scheduled_close_at) {
await thread.cancelScheduledClose();
thread.postSystemMessage(`Cancelled scheduled closing`);
}
return;
}
// Set a timed close
const delay = utils.convertDelayStringToMS(args.join(' '));
if (delay === 0 || delay === null) {
thread.postSystemMessage(`Invalid delay specified. Format: "1h30m"`);
return;
}
const closeAt = moment.utc().add(delay, 'ms');
await thread.scheduleClose(closeAt.format('YYYY-MM-DD HH:mm:ss'), msg.author);
thread.postSystemMessage(`Thread is now scheduled to be closed in ${humanizeDelay(delay)}. Use \`${config.prefix}close cancel\` to cancel.`);
return;
}
// Regular close
await thread.close();
const logUrl = await thread.getLogUrl();
utils.postLog(utils.trimAll(`
Modmail thread with ${thread.user_name} (${thread.user_id}) was closed by ${msg.author.username}
Logs: ${logUrl}
`));
});
module.exports = { module.exports = {
async start() { async start() {
// Load plugins // Load modules
console.log('Loading plugins...'); console.log('Loading modules...');
await logCommands(bot); await reply(bot);
await blocking(bot); await close(bot);
await moving(bot); await logs(bot);
await block(bot);
await move(bot);
await snippets(bot); await snippets(bot);
await suspending(bot); await suspend(bot);
await greeting(bot); await greeting(bot);
await webserver(bot); await webserver(bot);
await typingProxy(bot);
// Connect to Discord // Connect to Discord
console.log('Connecting to Discord...'); console.log('Connecting to Discord...');
await bot.connect(); await bot.connect();
// Start scheduled close loop
scheduledCloseLoop();
console.log('Done! Now listening to DMs.');
} }
}; };

95
src/modules/close.js Normal file
View File

@ -0,0 +1,95 @@
const humanizeDuration = require('humanize-duration');
const moment = require('moment');
const Eris = require('eris');
const config = require('../config');
const threadUtils = require('../threadUtils');
const utils = require("../utils");
const threads = require("../data/threads");
module.exports = bot => {
const addInboxServerCommand = (...args) => threadUtils.addInboxServerCommand(bot, ...args);
const humanizeDelay = (delay, opts = {}) => humanizeDuration(delay, Object.assign({conjunction: ' and '}, opts));
// Check for threads that are scheduled to be closed and close them
async function applyScheduledCloses() {
const threadsToBeClosed = await threads.getThreadsThatShouldBeClosed();
for (const thread of threadsToBeClosed) {
await thread.close();
const logUrl = await thread.getLogUrl();
utils.postLog(utils.trimAll(`
Modmail thread with ${thread.user_name} (${thread.user_id}) was closed as scheduled by ${thread.scheduled_close_name}
Logs: ${logUrl}
`));
}
}
async function scheduledCloseLoop() {
try {
await applyScheduledCloses();
} catch (e) {
console.error(e);
}
setTimeout(scheduledCloseLoop, 2000);
}
scheduledCloseLoop();
// Close a thread. Closing a thread saves a log of the channel's contents and then deletes the channel.
addInboxServerCommand('close', async (msg, args, thread) => {
if (! thread) return;
// Timed close
if (args.length) {
if (args[0] === 'cancel') {
// Cancel timed close
if (thread.scheduled_close_at) {
await thread.cancelScheduledClose();
thread.postSystemMessage(`Cancelled scheduled closing`);
}
return;
}
// Set a timed close
const delay = utils.convertDelayStringToMS(args.join(' '));
if (delay === 0 || delay === null) {
thread.postSystemMessage(`Invalid delay specified. Format: "1h30m"`);
return;
}
const closeAt = moment.utc().add(delay, 'ms');
await thread.scheduleClose(closeAt.format('YYYY-MM-DD HH:mm:ss'), msg.author);
thread.postSystemMessage(`Thread is now scheduled to be closed in ${humanizeDelay(delay)}. Use \`${config.prefix}close cancel\` to cancel.`);
return;
}
// Regular close
await thread.close();
const logUrl = await thread.getLogUrl();
utils.postLog(utils.trimAll(`
Modmail thread with ${thread.user_name} (${thread.user_id}) was closed by ${msg.author.username}
Logs: ${logUrl}
`));
});
// Auto-close threads if their channel is deleted
bot.on('channelDelete', async (channel) => {
if (! (channel instanceof Eris.TextChannel)) return;
if (channel.guild.id !== utils.getInboxGuild().id) return;
const thread = await threads.findOpenThreadByChannelId(channel.id);
if (! thread) return;
console.log(`[INFO] Auto-closing thread with ${thread.user_name} because the channel was deleted`);
await thread.close(true);
const logUrl = await thread.getLogUrl();
utils.postLog(utils.trimAll(`
Modmail thread with ${thread.user_name} (${thread.user_id}) was closed automatically because the channel was deleted
Logs: ${logUrl}
`));
});
};

31
src/modules/reply.js Normal file
View File

@ -0,0 +1,31 @@
const attachments = require("../data/attachments");
const threadUtils = require("../threadUtils");
module.exports = bot => {
const addInboxServerCommand = (...args) => threadUtils.addInboxServerCommand(bot, ...args);
// 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
addInboxServerCommand('reply', async (msg, args, thread) => {
if (! thread) return;
const text = args.join(' ').trim();
if (msg.attachments.length) await attachments.saveAttachmentsInMessage(msg);
await thread.replyToUser(msg.member, text, msg.attachments, false);
msg.delete();
});
bot.registerCommandAlias('r', 'reply');
// Anonymous replies only show the role, not the username
addInboxServerCommand('anonreply', async (msg, args, thread) => {
if (! thread) return;
const text = args.join(' ').trim();
if (msg.attachments.length) await attachments.saveAttachmentsInMessage(msg);
await thread.replyToUser(msg.member, text, msg.attachments, true);
msg.delete();
});
bot.registerCommandAlias('ar', 'anonreply');
};

View File

@ -0,0 +1,33 @@
const config = require('../config');
const threads = require("../data/threads");
const Eris = require("eris");
module.exports = bot => {
// Typing proxy: forwarding typing events between the DM and the modmail thread
if(config.typingProxy || config.typingProxyReverse) {
bot.on("typingStart", async (channel, user) => {
// config.typingProxy: forward user typing in a DM to the modmail thread
if (config.typingProxy && (channel instanceof Eris.PrivateChannel)) {
const thread = await threads.findOpenThreadByUserId(user.id);
if (! thread) return;
try {
await bot.sendChannelTyping(thread.channel_id);
} catch (e) {}
}
// config.typingProxyReverse: forward moderator typing in a thread to the DM
else if (config.typingProxyReverse && (channel instanceof Eris.GuildChannel) && ! user.bot) {
const thread = await threads.findByChannelId(channel.id);
if (! thread) return;
const dmChannel = await thread.getDMChannel();
if (! dmChannel) return;
try {
await bot.sendChannelTyping(dmChannel.id);
} catch(e) {}
}
});
}
};