Add support for scheduled !suspend
parent
bee147c19d
commit
688ab7ceea
|
@ -0,0 +1,15 @@
|
||||||
|
exports.up = async function(knex, Promise) {
|
||||||
|
await knex.schema.table('threads', table => {
|
||||||
|
table.dateTime('scheduled_suspend_at').index().nullable().defaultTo(null).after('channel_id');
|
||||||
|
table.string('scheduled_suspend_id', 20).nullable().defaultTo(null).after('channel_id');
|
||||||
|
table.string('scheduled_suspend_name', 128).nullable().defaultTo(null).after('channel_id');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = async function(knex, Promise) {
|
||||||
|
await knex.schema.table('threads', table => {
|
||||||
|
table.dropColumn('scheduled_suspend_at');
|
||||||
|
table.dropColumn('scheduled_suspend_id');
|
||||||
|
table.dropColumn('scheduled_suspend_name');
|
||||||
|
});
|
||||||
|
};
|
|
@ -356,6 +356,7 @@ class Thread {
|
||||||
/**
|
/**
|
||||||
* @param {String} time
|
* @param {String} time
|
||||||
* @param {Eris~User} user
|
* @param {Eris~User} user
|
||||||
|
* @param {Number} silent
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async scheduleClose(time, user, silent) {
|
async scheduleClose(time, user, silent) {
|
||||||
|
@ -390,7 +391,10 @@ class Thread {
|
||||||
await knex('threads')
|
await knex('threads')
|
||||||
.where('id', this.id)
|
.where('id', this.id)
|
||||||
.update({
|
.update({
|
||||||
status: THREAD_STATUS.SUSPENDED
|
status: THREAD_STATUS.SUSPENDED,
|
||||||
|
scheduled_suspend_at: null,
|
||||||
|
scheduled_suspend_id: null,
|
||||||
|
scheduled_suspend_name: null
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,6 +409,34 @@ class Thread {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} time
|
||||||
|
* @param {Eris~User} user
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async scheduleSuspend(time, user) {
|
||||||
|
await knex('threads')
|
||||||
|
.where('id', this.id)
|
||||||
|
.update({
|
||||||
|
scheduled_suspend_at: time,
|
||||||
|
scheduled_suspend_id: user.id,
|
||||||
|
scheduled_suspend_name: user.username
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async cancelScheduledSuspend() {
|
||||||
|
await knex('threads')
|
||||||
|
.where('id', this.id)
|
||||||
|
.update({
|
||||||
|
scheduled_suspend_at: null,
|
||||||
|
scheduled_suspend_id: null,
|
||||||
|
scheduled_suspend_name: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} userId
|
* @param {String} userId
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
|
|
|
@ -273,6 +273,18 @@ async function getThreadsThatShouldBeClosed() {
|
||||||
return threads.map(thread => new Thread(thread));
|
return threads.map(thread => new Thread(thread));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getThreadsThatShouldBeSuspended() {
|
||||||
|
const now = moment.utc().format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
const threads = await knex('threads')
|
||||||
|
.where('status', THREAD_STATUS.OPEN)
|
||||||
|
.whereNotNull('scheduled_suspend_at')
|
||||||
|
.where('scheduled_suspend_at', '<=', now)
|
||||||
|
.whereNotNull('scheduled_suspend_at')
|
||||||
|
.select();
|
||||||
|
|
||||||
|
return threads.map(thread => new Thread(thread));
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
findById,
|
findById,
|
||||||
findOpenThreadByUserId,
|
findOpenThreadByUserId,
|
||||||
|
@ -283,5 +295,6 @@ module.exports = {
|
||||||
getClosedThreadsByUserId,
|
getClosedThreadsByUserId,
|
||||||
findOrCreateThreadForUser,
|
findOrCreateThreadForUser,
|
||||||
getThreadsThatShouldBeClosed,
|
getThreadsThatShouldBeClosed,
|
||||||
|
getThreadsThatShouldBeSuspended,
|
||||||
createThreadInDB
|
createThreadInDB
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
const humanizeDuration = require('humanize-duration');
|
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const Eris = require('eris');
|
const Eris = require('eris');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
|
@ -8,8 +7,6 @@ const blocked = require('../data/blocked');
|
||||||
const {messageQueue} = require('../queue');
|
const {messageQueue} = require('../queue');
|
||||||
|
|
||||||
module.exports = bot => {
|
module.exports = bot => {
|
||||||
const humanizeDelay = (delay, opts = {}) => humanizeDuration(delay, Object.assign({conjunction: ' and '}, opts));
|
|
||||||
|
|
||||||
// Check for threads that are scheduled to be closed and close them
|
// Check for threads that are scheduled to be closed and close them
|
||||||
async function applyScheduledCloses() {
|
async function applyScheduledCloses() {
|
||||||
const threadsToBeClosed = await threads.getThreadsThatShouldBeClosed();
|
const threadsToBeClosed = await threads.getThreadsThatShouldBeClosed();
|
||||||
|
@ -90,7 +87,6 @@ module.exports = bot => {
|
||||||
// Timed close
|
// Timed close
|
||||||
const delayStringArg = args.find(arg => utils.delayStringRegex.test(arg));
|
const delayStringArg = args.find(arg => utils.delayStringRegex.test(arg));
|
||||||
if (delayStringArg) {
|
if (delayStringArg) {
|
||||||
// Set a timed close
|
|
||||||
const delay = utils.convertDelayStringToMS(delayStringArg);
|
const delay = utils.convertDelayStringToMS(delayStringArg);
|
||||||
if (delay === 0 || delay === null) {
|
if (delay === 0 || delay === null) {
|
||||||
thread.postSystemMessage(`Invalid delay specified. Format: "1h30m"`);
|
thread.postSystemMessage(`Invalid delay specified. Format: "1h30m"`);
|
||||||
|
@ -102,9 +98,9 @@ module.exports = bot => {
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
if (silentClose) {
|
if (silentClose) {
|
||||||
response = `Thread is now scheduled to be closed silently in ${humanizeDelay(delay)}. Use \`${config.prefix}close cancel\` to cancel.`;
|
response = `Thread is now scheduled to be closed silently in ${utils.humanizeDelay(delay)}. Use \`${config.prefix}close cancel\` to cancel.`;
|
||||||
} else {
|
} else {
|
||||||
response = `Thread is now scheduled to be closed in ${humanizeDelay(delay)}. Use \`${config.prefix}close cancel\` to cancel.`;
|
response = `Thread is now scheduled to be closed in ${utils.humanizeDelay(delay)}. Use \`${config.prefix}close cancel\` to cancel.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread.postSystemMessage(response);
|
thread.postSystemMessage(response);
|
||||||
|
|
|
@ -1,11 +1,70 @@
|
||||||
|
const moment = require('moment');
|
||||||
const threadUtils = require('../threadUtils');
|
const threadUtils = require('../threadUtils');
|
||||||
const threads = require("../data/threads");
|
const threads = require("../data/threads");
|
||||||
|
const utils = require('../utils');
|
||||||
|
const config = require('../config');
|
||||||
|
|
||||||
|
const {THREAD_STATUS} = require('../data/constants');
|
||||||
|
|
||||||
module.exports = bot => {
|
module.exports = bot => {
|
||||||
const addInboxServerCommand = (...args) => threadUtils.addInboxServerCommand(bot, ...args);
|
const addInboxServerCommand = (...args) => threadUtils.addInboxServerCommand(bot, ...args);
|
||||||
|
|
||||||
|
// Check for threads that are scheduled to be suspended and suspend them
|
||||||
|
async function applyScheduledSuspensions() {
|
||||||
|
const threadsToBeSuspended = await threads.getThreadsThatShouldBeSuspended();
|
||||||
|
for (const thread of threadsToBeSuspended) {
|
||||||
|
if (thread.status === THREAD_STATUS.OPEN) {
|
||||||
|
await thread.suspend();
|
||||||
|
await thread.postSystemMessage(`**Thread suspended** as scheduled by ${thread.scheduled_suspend_name}. This thread will act as closed until unsuspended with \`!unsuspend\``);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function scheduledSuspendLoop() {
|
||||||
|
try {
|
||||||
|
await applyScheduledSuspensions();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(scheduledSuspendLoop, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduledSuspendLoop();
|
||||||
|
|
||||||
addInboxServerCommand('suspend', async (msg, args, thread) => {
|
addInboxServerCommand('suspend', async (msg, args, thread) => {
|
||||||
if (! thread) return;
|
if (! thread) return;
|
||||||
|
|
||||||
|
if (args.length) {
|
||||||
|
// Cancel timed suspend
|
||||||
|
if (args.includes('cancel') || args.includes('c')) {
|
||||||
|
// Cancel timed suspend
|
||||||
|
if (thread.scheduled_suspend_at) {
|
||||||
|
await thread.cancelScheduledSuspend();
|
||||||
|
thread.postSystemMessage(`Cancelled scheduled suspension`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timed suspend
|
||||||
|
const delayStringArg = args.find(arg => utils.delayStringRegex.test(arg));
|
||||||
|
if (delayStringArg) {
|
||||||
|
const delay = utils.convertDelayStringToMS(delayStringArg);
|
||||||
|
if (delay === 0 || delay === null) {
|
||||||
|
thread.postSystemMessage(`Invalid delay specified. Format: "1h30m"`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const suspendAt = moment.utc().add(delay, 'ms');
|
||||||
|
await thread.scheduleSuspend(suspendAt.format('YYYY-MM-DD HH:mm:ss'), msg.author);
|
||||||
|
|
||||||
|
thread.postSystemMessage(`Thread will be suspended in ${utils.humanizeDelay(delay)}. Use \`${config.prefix}suspend cancel\` to cancel.`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await thread.suspend();
|
await thread.suspend();
|
||||||
thread.postSystemMessage(`**Thread suspended!** This thread will act as closed until unsuspended with \`!unsuspend\``);
|
thread.postSystemMessage(`**Thread suspended!** This thread will act as closed until unsuspended with \`!unsuspend\``);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const Eris = require('eris');
|
const Eris = require('eris');
|
||||||
const bot = require('./bot');
|
const bot = require('./bot');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
const humanizeDuration = require('humanize-duration');
|
||||||
const publicIp = require('public-ip');
|
const publicIp = require('public-ip');
|
||||||
const attachments = require('./data/attachments');
|
const attachments = require('./data/attachments');
|
||||||
const config = require('./config');
|
const config = require('./config');
|
||||||
|
@ -293,6 +294,8 @@ function isSnowflake(str) {
|
||||||
return snowflakeRegex.test(str);
|
return snowflakeRegex.test(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const humanizeDelay = (delay, opts = {}) => humanizeDuration(delay, Object.assign({conjunction: ' and '}, opts));
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
BotError,
|
BotError,
|
||||||
|
|
||||||
|
@ -324,4 +327,6 @@ module.exports = {
|
||||||
setDataModelProps,
|
setDataModelProps,
|
||||||
|
|
||||||
isSnowflake,
|
isSnowflake,
|
||||||
|
|
||||||
|
humanizeDelay,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue