Rename requiredJoinedAt -> requiredTimeOnServer, add support for multiple main guilds for that setting
parent
3ad2d0a2ff
commit
22e03d2335
|
@ -81,7 +81,7 @@ These go in `config.json`. See also `config.example.json`.
|
||||||
|greetingMessage|None|Text content of the welcome message|
|
|greetingMessage|None|Text content of the welcome message|
|
||||||
|ignoreAccidentalThreads|false|If set to true, the bot attempts to ignore common "accidental" messages that would start a new thread, such as "ok", "thanks", etc.|
|
|ignoreAccidentalThreads|false|If set to true, the bot attempts to ignore common "accidental" messages that would start a new thread, such as "ok", "thanks", etc.|
|
||||||
|inboxServerPermission|None|Permission required to use bot commands on the inbox server|
|
|inboxServerPermission|None|Permission required to use bot commands on the inbox server|
|
||||||
|joinedAtDeniedMessage|"You haven't been a member of the server for enough time to contact modmail"|See `requiredJoinedAt` below|
|
|timeOnServerDeniedMessage|"You haven't been a member of the server for long enough to contact modmail."|See `requiredTimeOnServer` below|
|
||||||
|mentionRole|"here"|Role that is mentioned when new threads are created or the bot is mentioned. Accepted values are "here", "everyone", or a role id as a string. Set to null to disable these pings entirely.|
|
|mentionRole|"here"|Role that is mentioned when new threads are created or the bot is mentioned. Accepted values are "here", "everyone", or a role id as a string. Set to null to disable these pings entirely.|
|
||||||
|mentionUserInThreadHeader|false|If set to true, mentions the thread's user in the thread header|
|
|mentionUserInThreadHeader|false|If set to true, mentions the thread's user in the thread header|
|
||||||
|newThreadCategoryId|None|ID of the category where new modmail thread channels should be placed|
|
|newThreadCategoryId|None|ID of the category where new modmail thread channels should be placed|
|
||||||
|
@ -90,7 +90,7 @@ These go in `config.json`. See also `config.example.json`.
|
||||||
|prefix|"!"|Prefix for bot commands|
|
|prefix|"!"|Prefix for bot commands|
|
||||||
|relaySmallAttachmentsAsAttachments|false|Whether to relay small attachments from users as native attachments rather than links in modmail threads|
|
|relaySmallAttachmentsAsAttachments|false|Whether to relay small attachments from users as native attachments rather than links in modmail threads|
|
||||||
|requiredAccountAge|None|Required account age for contacting modmail (in hours). If the account is not old enough, a new thread will not be created and the bot will reply with `accountAgeDeniedMessage` (if set) instead.|
|
|requiredAccountAge|None|Required account age for contacting modmail (in hours). If the account is not old enough, a new thread will not be created and the bot will reply with `accountAgeDeniedMessage` (if set) instead.|
|
||||||
|requiredJoinedAt|None|Required amount of time (in hours) the user must be a member of the server before being able to contact modmail. If the user hasn't been a member of the server for the specified time, a new thread will not be created and the bot will reply with `joinedAtDeniedMessage` (if set) instead. Only works if one main guild has been set.|
|
|requiredTimeOnServer|None|Required amount of time (in minutes) the user must be a member of the server before being able to contact modmail. If the user hasn't been a member of the server for the specified time, a new thread will not be created and the bot will reply with `timeOnServerDeniedMessage` (if set) instead.|
|
||||||
|responseMessage|"Thank you for your message! Our mod team will reply to you here as soon as possible."|The bot's response to DMs that start a new thread|
|
|responseMessage|"Thank you for your message! Our mod team will reply to you here as soon as possible."|The bot's response to DMs that start a new thread|
|
||||||
|smallAttachmentLimit|2097152|Size limit of `relaySmallAttachmentsAsAttachments`, in bytes (default is 2MB)|
|
|smallAttachmentLimit|2097152|Size limit of `relaySmallAttachmentsAsAttachments`, in bytes (default is 2MB)|
|
||||||
|snippetPrefix|"!!"|Prefix to use snippets|
|
|snippetPrefix|"!!"|Prefix to use snippets|
|
||||||
|
|
|
@ -78,8 +78,8 @@ const defaultConfig = {
|
||||||
"requiredAccountAge": null, // In hours
|
"requiredAccountAge": null, // In hours
|
||||||
"accountAgeDeniedMessage": "Your Discord account is not old enough to contact modmail.",
|
"accountAgeDeniedMessage": "Your Discord account is not old enough to contact modmail.",
|
||||||
|
|
||||||
"requiredJoinedAt": null, // In hours too
|
"requiredTimeOnServer": null, // In minutes
|
||||||
"joinedAtDeniedMessage": "You haven't been a member of the server for enough time to contact modmail",
|
"timeOnServerDeniedMessage": "You haven't been a member of the server for long enough to contact modmail.",
|
||||||
|
|
||||||
"relaySmallAttachmentsAsAttachments": false,
|
"relaySmallAttachmentsAsAttachments": false,
|
||||||
"smallAttachmentLimit": 1024 * 1024 * 2,
|
"smallAttachmentLimit": 1024 * 1024 * 2,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const Eris = require('eris');
|
const {User, Member} = require('eris');
|
||||||
|
|
||||||
const transliterate = require('transliteration');
|
const transliterate = require('transliteration');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const uuid = require('uuid');
|
const uuid = require('uuid');
|
||||||
|
@ -12,6 +13,9 @@ const utils = require('../utils');
|
||||||
const Thread = require('./Thread');
|
const Thread = require('./Thread');
|
||||||
const {THREAD_STATUS} = require('./constants');
|
const {THREAD_STATUS} = require('./constants');
|
||||||
|
|
||||||
|
const MINUTES = 60 * 1000;
|
||||||
|
const HOURS = 60 * MINUTES;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} id
|
* @param {String} id
|
||||||
* @returns {Promise<Thread>}
|
* @returns {Promise<Thread>}
|
||||||
|
@ -46,33 +50,22 @@ function getHeaderGuildInfo(member) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new modmail thread for the specified user
|
* Creates a new modmail thread for the specified user
|
||||||
* @param {Eris.User} user
|
* @param {User} user
|
||||||
|
* @param {Member} member
|
||||||
* @param {Boolean} quiet If true, doesn't ping mentionRole or reply with responseMessage
|
* @param {Boolean} quiet If true, doesn't ping mentionRole or reply with responseMessage
|
||||||
* @returns {Promise<Thread>}
|
* @returns {Promise<Thread|undefined>}
|
||||||
* @throws {Error}
|
* @throws {Error}
|
||||||
*/
|
*/
|
||||||
async function createNewThreadForUser(user, member, quiet = false) {
|
async function createNewThreadForUser(user, quiet = false) {
|
||||||
const existingThread = await findOpenThreadByUserId(user.id);
|
const existingThread = await findOpenThreadByUserId(user.id);
|
||||||
if (existingThread) {
|
if (existingThread) {
|
||||||
throw new Error('Attempted to create a new thread for a user with an existing open thread!');
|
throw new Error('Attempted to create a new thread for a user with an existing open thread!');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the config for a requirement of a minimum time the user must be a member of the guild to contact modmail,
|
// If set in config, check that the user's account is old enough (time since they registered on Discord)
|
||||||
// if the user hasn't been a member of the guild for the specified time, return an optional message without making a new thread
|
// If the account is too new, don't start a new thread and optionally reply to them with a message
|
||||||
if (config.requiredJoinedAt && member) {
|
|
||||||
if (member.joinedAt > moment() - config.requiredJoinedAt) {
|
|
||||||
if (config.joinedAtDeniedMessage) {
|
|
||||||
const privateChannel = await user.getDMChannel();
|
|
||||||
await privateChannel.createMessage(config.joinedAtDeniedMessage);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the config for a requirement of account age to contact modmail,
|
|
||||||
// if the account is too young, return an optional message without making a new thread
|
|
||||||
if (config.requiredAccountAge) {
|
if (config.requiredAccountAge) {
|
||||||
if (user.createdAt > moment() - config.requiredAccountAge * 3600000){
|
if (user.createdAt > moment() - config.requiredAccountAge * HOURS){
|
||||||
if (config.accountAgeDeniedMessage) {
|
if (config.accountAgeDeniedMessage) {
|
||||||
const privateChannel = await user.getDMChannel();
|
const privateChannel = await user.getDMChannel();
|
||||||
await privateChannel.createMessage(config.accountAgeDeniedMessage);
|
await privateChannel.createMessage(config.accountAgeDeniedMessage);
|
||||||
|
@ -81,16 +74,6 @@ async function createNewThreadForUser(user, member, quiet = false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the user's name+discrim for the thread channel's name
|
|
||||||
// Channel names are particularly picky about what characters they allow, so we gotta do some clean-up
|
|
||||||
let cleanName = transliterate.slugify(user.username);
|
|
||||||
if (cleanName === '') cleanName = 'unknown';
|
|
||||||
cleanName = cleanName.slice(0, 95); // Make sure the discrim fits
|
|
||||||
|
|
||||||
const channelName = `${cleanName}-${user.discriminator}`;
|
|
||||||
|
|
||||||
console.log(`[NOTE] Creating new thread channel ${channelName}`);
|
|
||||||
|
|
||||||
// Find which main guilds this user is part of
|
// Find which main guilds this user is part of
|
||||||
const mainGuilds = utils.getMainGuilds();
|
const mainGuilds = utils.getMainGuilds();
|
||||||
const userGuildData = new Map();
|
const userGuildData = new Map();
|
||||||
|
@ -111,6 +94,34 @@ async function createNewThreadForUser(user, member, quiet = false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If set in config, check that the user has been a member of one of the main guilds long enough
|
||||||
|
// If they haven't, don't start a new thread and optionally reply to them with a message
|
||||||
|
if (config.requiredTimeOnServer) {
|
||||||
|
// Check if the user joined any of the main servers a long enough time ago
|
||||||
|
// If we don't see this user on any of the main guilds (the size check below), assume we're just missing some data and give the user the benefit of the doubt
|
||||||
|
const isAllowed = userGuildData.size === 0 || Array.from(userGuildData.values()).some(({guild, member}) => {
|
||||||
|
return member.joinedAt < moment() - config.requiredTimeOnServer * MINUTES;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (! isAllowed) {
|
||||||
|
if (config.timeOnServerDeniedMessage) {
|
||||||
|
const privateChannel = await user.getDMChannel();
|
||||||
|
await privateChannel.createMessage(config.timeOnServerDeniedMessage);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the user's name+discrim for the thread channel's name
|
||||||
|
// Channel names are particularly picky about what characters they allow, so we gotta do some clean-up
|
||||||
|
let cleanName = transliterate.slugify(user.username);
|
||||||
|
if (cleanName === '') cleanName = 'unknown';
|
||||||
|
cleanName = cleanName.slice(0, 95); // Make sure the discrim fits
|
||||||
|
|
||||||
|
const channelName = `${cleanName}-${user.discriminator}`;
|
||||||
|
|
||||||
|
console.log(`[NOTE] Creating new thread channel ${channelName}`);
|
||||||
|
|
||||||
// Figure out which category we should place the thread channel in
|
// Figure out which category we should place the thread channel in
|
||||||
let newThreadCategoryId;
|
let newThreadCategoryId;
|
||||||
|
|
||||||
|
|
15
src/main.js
15
src/main.js
|
@ -74,25 +74,12 @@ bot.on('messageCreate', async msg => {
|
||||||
messageQueue.add(async () => {
|
messageQueue.add(async () => {
|
||||||
let thread = await threads.findOpenThreadByUserId(msg.author.id);
|
let thread = await threads.findOpenThreadByUserId(msg.author.id);
|
||||||
|
|
||||||
// Due the way discord works, private channels don't have a member property as they are a guild only property,
|
|
||||||
// if more than one main guild have been set, we just ignore the requiredJoinedAt config option
|
|
||||||
let member;
|
|
||||||
const mainGuilds = utils.getMainGuilds();
|
|
||||||
if (mainGuilds.length === 1) {
|
|
||||||
member = bot.guilds.get(mainGuilds[0]).members.get(msg.author.id);
|
|
||||||
if (! member) {
|
|
||||||
member = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
member = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// New thread
|
// New thread
|
||||||
if (! thread) {
|
if (! thread) {
|
||||||
// Ignore messages that shouldn't usually open new threads, such as "ok", "thanks", etc.
|
// Ignore messages that shouldn't usually open new threads, such as "ok", "thanks", etc.
|
||||||
if (config.ignoreAccidentalThreads && msg.content && ACCIDENTAL_THREAD_MESSAGES.includes(msg.content.trim().toLowerCase())) return;
|
if (config.ignoreAccidentalThreads && msg.content && ACCIDENTAL_THREAD_MESSAGES.includes(msg.content.trim().toLowerCase())) return;
|
||||||
|
|
||||||
thread = await threads.createNewThreadForUser(msg.author, member);
|
thread = await threads.createNewThreadForUser(msg.author);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread) await thread.receiveUserReply(msg);
|
if (thread) await thread.receiveUserReply(msg);
|
||||||
|
|
|
@ -17,24 +17,13 @@ module.exports = bot => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let member;
|
|
||||||
const mainGuilds = utils.getMainGuilds();
|
|
||||||
if (mainGuilds.length === 1) {
|
|
||||||
member = bot.guilds.get(mainGuilds[0]).members.get(msg.author.id);
|
|
||||||
if (! member) {
|
|
||||||
member = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
member = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const existingThread = await threads.findOpenThreadByUserId(user.id);
|
const existingThread = await threads.findOpenThreadByUserId(user.id);
|
||||||
if (existingThread) {
|
if (existingThread) {
|
||||||
utils.postSystemMessageWithFallback(msg.channel, thread, `Cannot create a new thread; there is another open thread with this user: <#${existingThread.channel_id}>`);
|
utils.postSystemMessageWithFallback(msg.channel, thread, `Cannot create a new thread; there is another open thread with this user: <#${existingThread.channel_id}>`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdThread = await threads.createNewThreadForUser(user, member, true);
|
const createdThread = await threads.createNewThreadForUser(user, true);
|
||||||
createdThread.postSystemMessage(`Thread was opened by ${msg.author.username}#${msg.author.discriminator}`);
|
createdThread.postSystemMessage(`Thread was opened by ${msg.author.username}#${msg.author.discriminator}`);
|
||||||
|
|
||||||
if (thread) {
|
if (thread) {
|
||||||
|
|
Loading…
Reference in New Issue