Add support for timed blocks. Add !is_blocked.
parent
4bfd247be3
commit
1259669c9d
|
@ -35,10 +35,11 @@ See [CHANGELOG.md](CHANGELOG.md)
|
|||
`!logs <user>` Lists previous modmail logs with the specified user
|
||||
`!block <user>` Blocks the specified user from using modmail
|
||||
`!unblock <user>` Unblocks the specified user from using modmail
|
||||
`!is_blocked <user>` Checks whether the user is blocked and for how long
|
||||
`!s <shortcut> <text>` Adds a snippet (a canned response). See below for how to use it.
|
||||
`!edit_snippet <shortcut> <text>` Edits an existing snippet (alias `!es`)
|
||||
`!delete_snippet <shortcut>` Deletes the specified snippet (alias `!ds`)
|
||||
`!snippets` Lists all available snippets
|
||||
`!snippets` Lists all available snippets
|
||||
`!version` Print the version of the bot you're running
|
||||
`!newthread <user>` Opens a new thread with the specified user
|
||||
|
||||
|
@ -47,8 +48,8 @@ See [CHANGELOG.md](CHANGELOG.md)
|
|||
`!anonreply <text>` Sends an anonymous reply to the user in the format "Role: text" (alias `!ar`)
|
||||
`!close <time>` Closes the modmail thread. If a time is specified, the thread is scheduled to be closed later. Scheduled closing is cancelled if a message is sent to or received from the user.
|
||||
`!logs` Lists previous modmail logs with this user
|
||||
`!block` Blocks the user from using modmail
|
||||
`!unblock` Unblocks the user from using modmail
|
||||
`!block <time>` Blocks the user from using modmail. If a time is specified, the block is temporary.
|
||||
`!unblock <time>` Unblocks the user from using modmail. If a time is specified, the user will be scheduled to be unblocked after that time.
|
||||
`!!shortcut` Reply with a snippet. Replace `shortcut` with the snippet's actual shortcut.
|
||||
`!!!shortcut` Reply with a snippet anonymously. Replace `shortcut` with the snippet's actual shortcut.
|
||||
`!move <category>` If `allowMove` is enabled, moves the thread channel to the specified category
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
exports.up = async function(knex, Promise) {
|
||||
await knex.schema.table('blocked_users', table => {
|
||||
table.dateTime('expires_at').nullable();
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = async function(knex, Promise) {
|
||||
await knex.schema.table('blocked_users', table => {
|
||||
table.dropColumn('expires_at');
|
||||
});
|
||||
};
|
|
@ -1,17 +1,28 @@
|
|||
const moment = require('moment');
|
||||
const knex = require('../knex');
|
||||
|
||||
/**
|
||||
* @param {String} userId
|
||||
* @returns {Promise<{ isBlocked: boolean, expiresAt: string }>}
|
||||
*/
|
||||
async function getBlockStatus(userId) {
|
||||
const row = await knex('blocked_users')
|
||||
.where('user_id', userId)
|
||||
.first();
|
||||
|
||||
return {
|
||||
isBlocked: !! row,
|
||||
expiresAt: row && row.expires_at
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether userId is blocked
|
||||
* @param {String} userId
|
||||
* @returns {Promise<Boolean>}
|
||||
*/
|
||||
async function isBlocked(userId) {
|
||||
const row = await knex('blocked_users')
|
||||
.where('user_id', userId)
|
||||
.first();
|
||||
|
||||
return !! row;
|
||||
return (await getBlockStatus(userId)).isBlocked;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,7 +32,7 @@ async function isBlocked(userId) {
|
|||
* @param {String} blockedBy
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function block(userId, userName = '', blockedBy = null) {
|
||||
async function block(userId, userName = '', blockedBy = null, expiresAt = null) {
|
||||
if (await isBlocked(userId)) return;
|
||||
|
||||
return knex('blocked_users')
|
||||
|
@ -29,7 +40,8 @@ async function block(userId, userName = '', blockedBy = null) {
|
|||
user_id: userId,
|
||||
user_name: userName,
|
||||
blocked_by: blockedBy,
|
||||
blocked_at: moment.utc().format('YYYY-MM-DD HH:mm:ss')
|
||||
blocked_at: moment.utc().format('YYYY-MM-DD HH:mm:ss'),
|
||||
expires_at: expiresAt
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -44,8 +56,39 @@ async function unblock(userId) {
|
|||
.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the expiry time of the block for the given userId
|
||||
* @param {String} userId
|
||||
* @param {String} expiresAt
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function updateExpiryTime(userId, expiresAt) {
|
||||
return knex('blocked_users')
|
||||
.where('user_id', userId)
|
||||
.update({
|
||||
expires_at: expiresAt
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {String[]}
|
||||
*/
|
||||
async function getExpiredBlocks() {
|
||||
const now = moment.utc().format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
const blocks = await knex('blocked_users')
|
||||
.whereNotNull('expires_at')
|
||||
.where('expires_at', '<=', now)
|
||||
.select();
|
||||
|
||||
return blocks.map(block => block.user_id);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getBlockStatus,
|
||||
isBlocked,
|
||||
block,
|
||||
unblock,
|
||||
updateExpiryTime,
|
||||
getExpiredBlocks,
|
||||
};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
const humanizeDuration = require('humanize-duration');
|
||||
const moment = require('moment');
|
||||
const threadUtils = require('../threadUtils');
|
||||
const blocked = require("../data/blocked");
|
||||
const utils = require("../utils");
|
||||
|
@ -5,38 +7,95 @@ const utils = require("../utils");
|
|||
module.exports = bot => {
|
||||
const addInboxServerCommand = (...args) => threadUtils.addInboxServerCommand(bot, ...args);
|
||||
|
||||
addInboxServerCommand('block', (msg, args, thread) => {
|
||||
async function block(userId) {
|
||||
const user = bot.users.get(userId);
|
||||
await blocked.block(userId, (user ? `${user.username}#${user.discriminator}` : ''), msg.author.id);
|
||||
msg.channel.createMessage(`Blocked <@${userId}> (id ${userId}) from modmail`);
|
||||
async function removeExpiredBlocks() {
|
||||
const expiredBlocks = await blocked.getExpiredBlocks();
|
||||
const logChannel = utils.getLogChannel();
|
||||
for (const userId of expiredBlocks) {
|
||||
await blocked.unblock(userId);
|
||||
logChannel.createMessage(`Block of <@!${userId}> (id \`${userId}\`) expired`);
|
||||
}
|
||||
}
|
||||
|
||||
async function expiredBlockLoop() {
|
||||
try {
|
||||
removeExpiredBlocks();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
if (args.length > 0) {
|
||||
// User mention/id as argument
|
||||
const userId = utils.getUserMention(args.join(' '));
|
||||
if (! userId) return;
|
||||
block(userId);
|
||||
} else if (thread) {
|
||||
// Calling !block without args in a modmail thread blocks the user of that thread
|
||||
block(thread.user_id);
|
||||
setTimeout(expiredBlockLoop, 2000);
|
||||
}
|
||||
|
||||
bot.on('ready', expiredBlockLoop);
|
||||
|
||||
addInboxServerCommand('block', async (msg, args, thread) => {
|
||||
const userIdToBlock = args[0]
|
||||
? utils.getUserMention(args[0])
|
||||
: thread && thread.user_id;
|
||||
|
||||
if (! userIdToBlock) return;
|
||||
|
||||
const isBlocked = await blocked.isBlocked(userIdToBlock);
|
||||
if (isBlocked) {
|
||||
msg.channel.createMessage('User is already blocked');
|
||||
return;
|
||||
}
|
||||
|
||||
const expiryTime = args[1] ? utils.convertDelayStringToMS(args[1]) : null;
|
||||
const expiresAt = expiryTime
|
||||
? moment.utc().add(expiryTime, 'ms').format('YYYY-MM-DD HH:mm:ss')
|
||||
: null;
|
||||
|
||||
const user = bot.users.get(userIdToBlock);
|
||||
await blocked.block(userIdToBlock, (user ? `${user.username}#${user.discriminator}` : ''), msg.author.id, expiresAt);
|
||||
|
||||
if (expiresAt) {
|
||||
const humanized = humanizeDuration(expiryTime, { largest: 2, round: true });
|
||||
msg.channel.createMessage(`Blocked <@${userIdToBlock}> (id \`${userIdToBlock}\`) from modmail for ${humanized}`);
|
||||
} else {
|
||||
msg.channel.createMessage(`Blocked <@${userIdToBlock}> (id \`${userIdToBlock}\`) from modmail indefinitely`);
|
||||
}
|
||||
});
|
||||
|
||||
addInboxServerCommand('unblock', (msg, args, thread) => {
|
||||
async function unblock(userId) {
|
||||
await blocked.unblock(userId);
|
||||
msg.channel.createMessage(`Unblocked <@${userId}> (id ${userId}) from modmail`);
|
||||
}
|
||||
addInboxServerCommand('unblock', async (msg, args, thread) => {
|
||||
const userIdToUnblock = args[0]
|
||||
? utils.getUserMention(args[0])
|
||||
: thread && thread.user_id;
|
||||
|
||||
if (args.length > 0) {
|
||||
// User mention/id as argument
|
||||
const userId = utils.getUserMention(args.join(' '));
|
||||
if (! userId) return;
|
||||
unblock(userId);
|
||||
} else if (thread) {
|
||||
// Calling !unblock without args in a modmail thread unblocks the user of that thread
|
||||
unblock(thread.user_id);
|
||||
if (! userIdToUnblock) return;
|
||||
|
||||
const unblockDelay = args[1] ? utils.convertDelayStringToMS(args[1]) : null;
|
||||
const unblockAt = unblockDelay
|
||||
? moment.utc().add(unblockDelay, 'ms').format('YYYY-MM-DD HH:mm:ss')
|
||||
: null;
|
||||
|
||||
const user = bot.users.get(userIdToUnblock);
|
||||
if (unblockAt) {
|
||||
const humanized = humanizeDuration(unblockDelay, { largest: 2, round: true });
|
||||
await blocked.updateExpiryTime(userIdToUnblock, unblockAt);
|
||||
msg.channel.createMessage(`Scheduled <@${userIdToUnblock}> (id \`${userIdToUnblock}\`) to be unblocked in ${humanized}`);
|
||||
} else {
|
||||
await blocked.unblock(userIdToUnblock);
|
||||
msg.channel.createMessage(`Unblocked <@${userIdToUnblock}> (id ${userIdToUnblock}) from modmail`);
|
||||
}
|
||||
});
|
||||
|
||||
addInboxServerCommand('is_blocked', async (msg, args, thread) => {
|
||||
const userIdToCheck = args[0]
|
||||
? utils.getUserMention(args[0])
|
||||
: thread && thread.user_id;
|
||||
|
||||
if (! userIdToCheck) return;
|
||||
|
||||
const blockStatus = await blocked.getBlockStatus(userIdToCheck);
|
||||
if (blockStatus.isBlocked) {
|
||||
if (blockStatus.expiresAt) {
|
||||
msg.channel.createMessage(`<@!${userIdToCheck}> (id \`${userIdToCheck}\`) is blocked until ${blockStatus.expiresAt} (UTC)`);
|
||||
} else {
|
||||
msg.channel.createMessage(`<@!${userIdToCheck}> (id \`${userIdToCheck}\`) is blocked indefinitely`);
|
||||
}
|
||||
} else {
|
||||
msg.channel.createMessage(`<@!${userIdToCheck}> (id \`${userIdToCheck}\`) is NOT blocked`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -224,7 +224,7 @@ const delayStringRegex = /^([0-9]+)(?:([dhms])[a-z]*)?/i;
|
|||
/**
|
||||
* Turns a "delay string" such as "1h30m" to milliseconds
|
||||
* @param {String} str
|
||||
* @returns {Number}
|
||||
* @returns {Number|null}
|
||||
*/
|
||||
function convertDelayStringToMS(str) {
|
||||
let match;
|
||||
|
|
Loading…
Reference in New Issue