Move more code from main.js to individual module files. Rename plugins -> modules. Remove some obsolete comments.
parent
1431ab8c4e
commit
ab3d70008a
|
@ -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({
|
||||||
|
|
|
@ -20,6 +20,7 @@ module.exports = {
|
||||||
'thanks',
|
'thanks',
|
||||||
'ty',
|
'ty',
|
||||||
'k',
|
'k',
|
||||||
|
'kk',
|
||||||
'thank you',
|
'thank you',
|
||||||
'thanx',
|
'thanx',
|
||||||
'thnx',
|
'thnx',
|
||||||
|
|
179
src/main.js
179
src/main.js
|
@ -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.');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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}
|
||||||
|
`));
|
||||||
|
});
|
||||||
|
};
|
|
@ -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');
|
||||||
|
};
|
|
@ -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) {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue