guild logging & automod
This commit is contained in:
parent
8e1e5c6c24
commit
c023328d96
495
src/structure/components/observers/Automoderation.js
Normal file
495
src/structure/components/observers/Automoderation.js
Normal file
@ -0,0 +1,495 @@
|
||||
const { inspect } = require('util');
|
||||
const similarity = require('similarity');
|
||||
const { stripIndents } = require('common-tags');
|
||||
|
||||
const { Observer } = require('../../interfaces');
|
||||
const { BinaryTree, Util, FilterUtil } = require('../../../utilities');
|
||||
const { FilterPresets } = require('../../../constants');
|
||||
const { Warn, Mute, Kick, Softban, Ban } = require('../infractions');
|
||||
const { GuildWrapper } = require('../../client/wrappers');
|
||||
|
||||
const CONSTANTS = {
|
||||
Infractions: {
|
||||
WARN: Warn,
|
||||
MUTE: Mute,
|
||||
KICK: Kick,
|
||||
SOFTBAN: Softban,
|
||||
BAN: Ban
|
||||
}
|
||||
};
|
||||
|
||||
// TODO:
|
||||
// Clean up commented out code once testing of new code is done
|
||||
// Implement missing automod features
|
||||
|
||||
|
||||
module.exports = class AutoModeration extends Observer {
|
||||
|
||||
constructor(client) {
|
||||
|
||||
super(client, {
|
||||
name: 'autoModeration',
|
||||
priority: 1,
|
||||
disabled: false
|
||||
});
|
||||
|
||||
this.hooks = [
|
||||
['messageCreate', this.filterWords.bind(this)],
|
||||
['messageUpdate', this.filterWords.bind(this)],
|
||||
['messageCreate', this.flagMessages.bind(this)],
|
||||
['messageUpdate', this.flagMessages.bind(this)],
|
||||
['messageCreate', this.filterLinks.bind(this)],
|
||||
['messageUpdate', this.filterLinks.bind(this)],
|
||||
['messageCreate', this.filterInvites.bind(this)],
|
||||
['messageUpdate', this.filterInvites.bind(this)],
|
||||
['messageCreate', this.filterMentions.bind(this)]
|
||||
];
|
||||
|
||||
this.whitelist = new BinaryTree(this.client, FilterPresets.whitelist);
|
||||
this.executing = {};
|
||||
|
||||
}
|
||||
|
||||
async _moderate(action, wrapper, channel, member, reason, filterResult) {
|
||||
|
||||
// Prevent simultaneous execution of the same filter on the same user when spamming
|
||||
if (!this.executing[filterResult.filter]) this.executing[filterResult.filter] = [];
|
||||
if (this.executing[filterResult.filter].includes(member.id)) return;
|
||||
this.executing[filterResult.filter].push(member.id);
|
||||
|
||||
const InfractionClass = CONSTANTS.Infractions[action.type];
|
||||
const result = await this.client.moderationManager._handleTarget(InfractionClass, member, {
|
||||
wrapper,
|
||||
channel,
|
||||
executor: wrapper.guild.me,
|
||||
reason,
|
||||
duration: action.duration,
|
||||
points: action.points,
|
||||
expiration: action.expiration,
|
||||
silent: true, //Won't DM Users.
|
||||
force: false,
|
||||
data: {
|
||||
automoderation: filterResult
|
||||
}
|
||||
}).catch(this.logger.error.bind(this.logger));
|
||||
|
||||
await Util.wait(5000);
|
||||
this.executing[filterResult.filter].splice(this.executing[filterResult.filter].indexOf(member.id), 1);
|
||||
|
||||
}
|
||||
|
||||
async filterWords(message, edited) {
|
||||
|
||||
const { guild, author, channel, guildWrapper: wrapper } = message;
|
||||
if (!guild || author.bot) return;
|
||||
|
||||
const member = message.member || await guild.members.fetch(author.id).catch();
|
||||
const settings = await wrapper.settings();
|
||||
const { wordfilter: setting } = settings;
|
||||
const { bypass, ignore, enabled, silent, explicit, fuzzy, regex, whitelist, actions } = setting;
|
||||
const roles = member?.roles.cache.map((r) => r.id) || [];
|
||||
|
||||
if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
||||
|
||||
// Which message obj to work with
|
||||
const msg = edited || message;
|
||||
if (!msg.content) return;
|
||||
let log = `Message filter debug:`;
|
||||
log += `\nPre norm: ${msg.cleanContent}`;
|
||||
let content = null;
|
||||
try { // NOTE: Remove try-catch after debug
|
||||
content = Util.removeMarkdown(msg.cleanContent);
|
||||
if (!content) return;
|
||||
content = FilterUtil.normalise(content);
|
||||
} catch (err) {
|
||||
this.logger.error(`Error in message filtering:\n${err.stack}\n${msg.cleanContent}`);
|
||||
return;
|
||||
}
|
||||
log += `\nNormalised: ${content}`;
|
||||
|
||||
const catcher = (ln) => {
|
||||
return () => this.logger.debug(`Issue with promise on line ${ln}`);
|
||||
};
|
||||
|
||||
// match: what was matched |
|
||||
// matched: did it match at all ? |
|
||||
// matcher: what gets shown in the message logs |
|
||||
// _matcher: locally used variable for which word in the list triggered it |
|
||||
// type: which detection type matched it
|
||||
let filterResult = { filter: 'word', match: null, matched: false, matcher: null, _matcher: null, preset: false };
|
||||
const words = content.toLowerCase().replace(/[,?.!]/gu, '').split(' ').filter((elem) => elem.length);
|
||||
// Remove any potential bypass characters
|
||||
//const _words = words.map((word) => word.replace(/[.'*_?+"#%&=-]/gu, ''));
|
||||
|
||||
// 2. Filter explicit - no bypass checking (unless you count normalising the text, i.e. emoji letters => normal letters)
|
||||
if (explicit.length && !filterResult.matched) {
|
||||
|
||||
//filterResult = FilterUtil.filterExplicit(words, explicit);
|
||||
// if(filterResult)
|
||||
|
||||
for (const word of explicit) {
|
||||
//Do it like this instead of regex so it doesn't match stuff like Scunthorpe with cunt
|
||||
if (words.some((_word) => _word === word)) {
|
||||
log += `\nMessage matched with "${word}" in the explicit list.\nFull content: ${content}`;
|
||||
filterResult = {
|
||||
match: word,
|
||||
matched: true,
|
||||
matcher: 'explicit',
|
||||
_matcher: word,
|
||||
type: 'explicit'
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 3. Filter regex
|
||||
if (regex.length && !filterResult.matched) {
|
||||
|
||||
for (const reg of regex) {
|
||||
|
||||
const match = content.toLowerCase().match(new RegExp(`(?:^|\\s)(${reg})`, 'iu')); // (?:^|\\s) |un
|
||||
|
||||
if (match) {
|
||||
//log += `\next reg: ${tmp}`;
|
||||
const fullWord = words.find((word) => word.includes(match[1]));
|
||||
|
||||
let inWL = false;
|
||||
try { // This is for debugging only
|
||||
inWL = this.whitelist.find(fullWord);
|
||||
} catch (err) {
|
||||
this.logger.debug(fullWord, match[1], words);
|
||||
}
|
||||
if (inWL || whitelist.some((word) => word === fullWord)) continue;
|
||||
|
||||
log += `\nMessage matched with "${reg}" in the regex list.\nMatch: ${match[0]}, Full word: ${fullWord}\nFull content: ${content}`;
|
||||
filterResult = {
|
||||
match: fullWord,
|
||||
matched: true,
|
||||
_matcher: match[1].toLowerCase(),
|
||||
matcher: `Regex: __${reg}__`,
|
||||
type: 'regex'
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 4. Filter fuzzy
|
||||
if (fuzzy.length && !filterResult.matched) {
|
||||
|
||||
const text = words.join('').replace(/\s/u, '');
|
||||
let threshold = (0.93 - 0.133 * Math.log(text.length)).toFixed(3);
|
||||
if (threshold < 0.6) threshold = 0.6;
|
||||
else if (threshold > 0.9) threshold = 0.9;
|
||||
|
||||
outer:
|
||||
for (const _word of fuzzy) {
|
||||
|
||||
for (const word of words) {
|
||||
const sim = similarity(word, _word);
|
||||
let threshold = (0.93 - 0.133 * Math.log(word.length)).toFixed(3);
|
||||
if (threshold < 0.6) threshold = 0.6;
|
||||
else if (threshold > 0.9) threshold = 0.9;
|
||||
if (sim >= threshold && Math.abs(_word.length - word.length) <= 2) {
|
||||
if (this.whitelist.find(word) || whitelist.some((w) => w === word) && sim < 1) continue;
|
||||
log += `\nMessage matched with "${_word}" in fuzzy.\nMatched word: ${word}\nFull content: ${content}\nSimilarity: ${sim}\nThreshold: ${threshold}`;
|
||||
filterResult = {
|
||||
match: word,
|
||||
matched: true,
|
||||
_matcher: _word,
|
||||
matcher: `fuzzy [\`${_word}\`, \`${sim}\`, \`${threshold}\`]`,
|
||||
type: 'fuzzy'
|
||||
};
|
||||
break outer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const sim = similarity(text, _word);
|
||||
if (sim >= threshold && Math.abs(_word.length - text.length) <= 2) {
|
||||
if (this.whitelist.find(text) || whitelist.some((w) => w === text) && sim < 1) continue;
|
||||
log += `\nMessage matched with "${_word}" in fuzzy.\nMatched word: ${text}\nFull content: ${content}\nSimilarity: ${sim}\nThreshold: ${threshold}`;
|
||||
filterResult = {
|
||||
match: text,
|
||||
matched: true,
|
||||
_matcher: _word,
|
||||
matcher: `fuzzy [\`${_word}\`, \`${sim}\`, \`${threshold}\`]`,
|
||||
type: 'fuzzy'
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
//this.client.logger.debug(`Message did not match with "${_word}" in fuzzy.\nFull content: ${content}\nSimilarity: ${sim}\nThreshold: ${threshold}`);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 5. Remove message, inline response and add a reason to msg object
|
||||
if (!filterResult.matched) return;
|
||||
msg.filtered = filterResult;
|
||||
log += `\nFilter result: ${inspect(filterResult)}`;
|
||||
if (!silent) {
|
||||
const res = await this.client.rateLimiter.limitSend(msg.channel, wrapper.format('W_FILTER_DELETE', { user: author.id }), undefined, 'wordFilter').catch(catcher(255));
|
||||
//const res = await msg.formattedRespond('W_FILTER_DELETE', { params: { user: author.id } });
|
||||
//if (res) res.delete({ timeout: 10000 }).catch(catcher(240));
|
||||
setTimeout(() => {
|
||||
res.delete().catch(() => { /**/ });
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
// 6. Automated actions
|
||||
if (actions.length) {
|
||||
|
||||
let action = actions.find((act) => {
|
||||
return act.trigger.includes(filterResult._matcher);
|
||||
});
|
||||
if (!action) action = actions.find((act) => {
|
||||
return act.trigger === filterResult.type;
|
||||
});
|
||||
if (!action) action = actions.find((act) => {
|
||||
return act.trigger === 'generic';
|
||||
});
|
||||
|
||||
if (!action) {
|
||||
this.logger.debug(log);
|
||||
return this.client.rateLimiter.queueDelete(msg.channel, msg).catch(catcher(275));
|
||||
}
|
||||
|
||||
msg.filtered.sanctioned = true;
|
||||
this.client.rateLimiter.queueDelete(msg.channel, msg).catch(catcher(279));
|
||||
this.logger.debug(log + '\nSanctioned');
|
||||
|
||||
filterResult.filter = 'word';
|
||||
this._moderate(action, wrapper, channel, member, wrapper.format('W_FILTER_ACTION'), filterResult, message);
|
||||
|
||||
} else {
|
||||
this.client.rateLimiter.queueDelete(msg.channel, msg).catch(catcher(269));
|
||||
this.logger.debug(log);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async flagMessages(message, edited) {
|
||||
|
||||
const { guild, author, channel, guildWrapper: wrapper } = message;
|
||||
if (!guild || author.bot) return;
|
||||
|
||||
const member = message.member || await guild.members.fetch(author.id).catch();
|
||||
const settings = await wrapper.settings();
|
||||
const { wordwatcher: setting } = settings;
|
||||
const { words, bypass, ignore, channel: _logChannel } = setting;
|
||||
const roles = member?.roles.cache.map((r) => r.id) || [];
|
||||
|
||||
if (!_logChannel || words.length === 0 || roles.some((r) => bypass.includes(r.id)) || ignore.includes(channel.id)) return;
|
||||
|
||||
const logChannel = await wrapper.resolveChannel(_logChannel);
|
||||
const msg = edited || message;
|
||||
if (!msg.content) return;
|
||||
let content = null;
|
||||
try {
|
||||
content = FilterUtil.normalise(msg.cleanContent);
|
||||
} catch (err) {
|
||||
this.logger.error(`Error in message flag:\n${err.stack}\n${msg.cleanContent}`);
|
||||
return;
|
||||
}
|
||||
let match = null;
|
||||
|
||||
for (const reg of words) {
|
||||
|
||||
match = content.match(new RegExp(`(?:^|\\s)(${reg})`, 'iu'));
|
||||
|
||||
if (match) break;
|
||||
|
||||
}
|
||||
|
||||
if (!match) return;
|
||||
|
||||
const context = channel.messages.cache.sort((m1, m2) => m2.createdTimestamp - m1.createdTimestamp).first(5);
|
||||
const embed = {
|
||||
title: `⚠️ Word trigger in **#${channel.name}**`,
|
||||
description: stripIndents`
|
||||
**[Jump to message](${msg.link})**
|
||||
`, // ** User:** <@${ author.id }>
|
||||
color: 15120384,
|
||||
fields: context.reverse().reduce((acc, val) => {
|
||||
const text = val.content.length ? Util.escapeMarkdown(val.content).replace(match[1], '**__$&__**') : '**NO CONTENT**';
|
||||
acc.push({
|
||||
name: `${val.author.tag} (${val.author.id}) - ${val.id}`,
|
||||
value: text.length < 1024 ? text : text.substring(0, 1013) + '...'
|
||||
});
|
||||
if (text.length > 1024) acc.push({
|
||||
name: `\u200b`,
|
||||
value: '...' + text.substring(1013, 2034)
|
||||
});
|
||||
return acc;
|
||||
}, [])
|
||||
};
|
||||
|
||||
const sent = await logChannel.send({ embeds: [embed] }).catch((err) => {
|
||||
this.logger.error('Error in message flag:\n' + err.stack);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async filterLinks(message, edited) {
|
||||
|
||||
const { guild, author, channel, guildWrapper: wrapper } = message;
|
||||
if (!guild || author.bot) return;
|
||||
|
||||
const member = message.member || await guild.members.fetch(author.id).catch();
|
||||
const { resolver } = this.client;
|
||||
const settings = await wrapper.settings();
|
||||
const { linkfilter: setting } = settings;
|
||||
const { bypass, ignore, actions, silent, enabled, blacklist, whitelist, mode } = setting;
|
||||
if (!enabled) return;
|
||||
const roles = member?.roles.cache.map((r) => r.id) || [];
|
||||
|
||||
if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
||||
|
||||
const msg = edited || message;
|
||||
if (!msg.content) return;
|
||||
const content = msg.content.split('').join(''); //Copy the string...
|
||||
const linkRegG = /(https?:\/\/(www\.)?)?(?<domain>([a-z0-9-]{1,63}\.)?([a-z0-9-]{2,63})(\.[a-z0-9-]{2,63})(\.[a-z0-9-]{2,63})?)(\/\S*)?/iug;
|
||||
const linkReg = /(https?:\/\/(www\.)?)?(?<domain>([a-z0-9-]{1,63}\.)?([a-z0-9-]{2,63})(\.[a-z0-9-]{2,63})(\.[a-z0-9-]{2,63})?)(\/\S*)?/iu;
|
||||
let matches = content.match(linkRegG);
|
||||
if (!matches) matches = content.replace(/\s/u, '').match(linkRegG);
|
||||
if (!matches) return;
|
||||
let remove = false;
|
||||
const filterResult = {};
|
||||
const _whitelist = mode === 'whitelist';
|
||||
|
||||
for (const match of matches) {
|
||||
const { domain } = match.match(linkReg).groups;
|
||||
|
||||
// eslint-disable-next-line brace-style
|
||||
if (!_whitelist && blacklist.some((dom) => { return dom.includes(domain) || domain.includes(dom); })) {
|
||||
filterResult.match = domain;
|
||||
filterResult.matcher = 'link blacklist';
|
||||
remove = true;
|
||||
break;
|
||||
} else if (_whitelist) {
|
||||
// eslint-disable-next-line brace-style
|
||||
if (whitelist.some((dom) => { return dom.includes(domain) || domain.includes(dom); })) continue;
|
||||
const valid = await resolver.validateDomain(domain);
|
||||
if (!valid) continue;
|
||||
|
||||
filterResult.match = domain;
|
||||
filterResult.matcher = 'link whitelist';
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!remove) return;
|
||||
msg.filtered = filterResult;
|
||||
if (!silent) {
|
||||
const res = await this.client.rateLimiter.limitSend(msg.channel, wrapper.format('L_FILTER_DELETE', { user: author.id }), undefined, 'linkFilter');
|
||||
//const res = await msg.formattedRespond(`L_FILTER_DELETE`, { params: { user: author.id } });
|
||||
//if (res) res.delete({ timeout: 10000 });
|
||||
setTimeout(() => {
|
||||
res.delete().catch(() => { /**/ });
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
if (actions.length) {
|
||||
|
||||
let action = actions.find((act) => {
|
||||
return act.trigger.includes(filterResult.match);
|
||||
});
|
||||
if (!action) action = actions.find((act) => {
|
||||
return act.trigger === mode;
|
||||
});
|
||||
if (!action) action = actions.find((act) => {
|
||||
return act.trigger === 'generic';
|
||||
});
|
||||
|
||||
if (!action) this.client.rateLimiter.queueDelete(msg.channel, msg);
|
||||
|
||||
msg.filtered.sanctioned = true;
|
||||
this.client.rateLimiter.queueDelete(msg.channel, msg);
|
||||
//msg.delete();
|
||||
|
||||
filterResult.filter = 'link';
|
||||
this._moderate(action, guild, channel, member, wrapper.format('L_FILTER_ACTION', { domain: filterResult.match }), filterResult, message);
|
||||
|
||||
} else this.client.rateLimiter.queueDelete(msg.channel, msg); //msg.delete();
|
||||
|
||||
}
|
||||
|
||||
async filterInvites(message, edited) {
|
||||
|
||||
const { guild, author, channel, guildWrapper: wrapper } = message;
|
||||
if (!guild || author.bot) return;
|
||||
|
||||
const member = message.member || await guild.members.fetch(author.id).catch();
|
||||
const settings = await wrapper.settings();
|
||||
const { invitefilter: setting } = settings;
|
||||
const { bypass, ignore, actions, silent, enabled } = setting;
|
||||
if (!enabled) return;
|
||||
const roles = member?.roles.cache.map((r) => r.id) || [];
|
||||
|
||||
if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
||||
|
||||
const msg = edited || message;
|
||||
const { content } = msg;
|
||||
if (!content) return;
|
||||
|
||||
const reg = /((discord)?\s?\.?\s?gg\s?|discord(app)?\.com\/invite)\/\s?(?<code>[a-z0-9]+)/iu;
|
||||
const match = content.match(reg);
|
||||
if (!match) return;
|
||||
|
||||
const result = await guild.checkInvite(match.groups.code);
|
||||
if (!result) { // Doesn't resolve to the origin server
|
||||
|
||||
let action = null;
|
||||
if (actions.length) [action] = actions;
|
||||
|
||||
msg.filtered = {
|
||||
match: match[0],
|
||||
matcher: 'invites'
|
||||
};
|
||||
if (!action) return this.client.rateLimiter.queueDelete(msg.channel, msg); //msg.delete();
|
||||
if (!silent) {
|
||||
const res = await this.client.rateLimiter.limitSend(msg.channel, wrapper.format('I_FILTER_DELETE', { user: author.id }), undefined, 'inviteFilter');
|
||||
//if (res) res.delete({ timeout: 10000 });
|
||||
setTimeout(() => {
|
||||
res.delete().catch(() => { /**/ });
|
||||
}, 10000);
|
||||
}
|
||||
msg.filtered.sactioned = true;
|
||||
this.client.rateLimiter.queueDelete(msg.channel, msg);
|
||||
|
||||
this._moderate(action, guild, channel, member, wrapper.format('I_FILTER_ACTION'), { filtered: msg.filtered }, message);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async filterMentions(message) {
|
||||
|
||||
const { guild, author, channel, guildWrapper: wrapper } = message;
|
||||
if (!guild || author.bot) return;
|
||||
|
||||
const member = message.member || await guild.members.fetch(author.id).catch();
|
||||
const settings = await wrapper.settings();
|
||||
const { mentionfilter: setting, modpoints } = settings;
|
||||
const { bypass, ignore, enabled, silent, unique, mentions, actions } = setting;
|
||||
const roles = member?.roles.cache.map((r) => r.id) || [];
|
||||
|
||||
if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
||||
|
||||
const reg = /<@!?[0-9]{18,22}>/gu;
|
||||
const { content } = message;
|
||||
if (!content) return;
|
||||
//const mentions = content.match(reg);
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,11 +1,11 @@
|
||||
/* eslint-disable no-labels */
|
||||
const { MessageAttachment, WebhookClient } = require('discord.js');
|
||||
|
||||
const { Observer } = require('../../interfaces/');
|
||||
const Util = require('../../../Util');
|
||||
const { Constants: { EmbedLimits } } = require('../../../constants');
|
||||
const { stripIndents } = require('common-tags');
|
||||
const moment = require('moment');
|
||||
|
||||
const { Observer } = require('../../interfaces/');
|
||||
const { Util } = require('../../../utilities');
|
||||
const { Constants: { EmbedLimits } } = require('../../../constants');
|
||||
const { GuildWrapper } = require('../../client/wrappers');
|
||||
|
||||
const CONSTANTS = {
|
||||
@ -52,8 +52,8 @@ class GuildLogger extends Observer {
|
||||
|
||||
this.attachmentWebhook = new WebhookClient(
|
||||
{
|
||||
id: this.client._options.discord.moderation.attachments.webhook.id,
|
||||
token: this.client._options.discord.moderation.attachments.webhook.token
|
||||
id: process.env.MODERATION_WEHBHOOK_ID,
|
||||
token: process.env.MODERATION_WEHBHOOK_TOKEN
|
||||
}
|
||||
);
|
||||
|
||||
@ -104,7 +104,7 @@ class GuildLogger extends Observer {
|
||||
|
||||
const hook = await wrapper.getWebhook('messages');
|
||||
if (!hook) {
|
||||
this.client.logger.debug(`Missing messageLog hook in ${message.guild.name} (${message.guild.id})`);
|
||||
this.logger.debug(`Missing messageLog hook in ${message.guild.name} (${message.guild.id})`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -200,7 +200,7 @@ class GuildLogger extends Observer {
|
||||
|
||||
const upload = async (files) => {
|
||||
const attachmentMessage = await this.attachmentWebhook.send(null, files)
|
||||
.catch((error) => this.client.logger.error(error));
|
||||
.catch((error) => this.logger.error(error));
|
||||
attachmentMessage.attachments.map(
|
||||
(a) => uploaded.push(`[${a.filename} (${(a.size / CONSTANTS.IMAGES.MB_DIVIDER).toFixed(2)}mb)](${a.url})`)
|
||||
);
|
||||
@ -229,7 +229,7 @@ class GuildLogger extends Observer {
|
||||
}
|
||||
|
||||
await hook.send({ embeds: [embed], files: uploadedFiles }).catch((err) => {
|
||||
this.client.logger.error('Error in message delete:\n' + err.stack);
|
||||
this.logger.error('Error in message delete:\n' + err.stack);
|
||||
});
|
||||
|
||||
}
|
||||
@ -238,10 +238,9 @@ class GuildLogger extends Observer {
|
||||
|
||||
//Status: Should be complete, though additional testing might be necessary
|
||||
|
||||
const { guild, channel } = messages.first();
|
||||
const { guild, channel, guildWrapper: wrapper } = messages.first();
|
||||
if (!guild) return;
|
||||
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const settings = await wrapper.settings();
|
||||
const chatlogs = settings.messages;
|
||||
if (!chatlogs.channel) return;
|
||||
@ -311,7 +310,7 @@ class GuildLogger extends Observer {
|
||||
|
||||
const upload = async (files) => {
|
||||
const attachmentMessage = await this.attachmentWebhook.send(null, files)
|
||||
.catch((error) => this.client.logger.error(error));
|
||||
.catch((error) => this.logger.error(error));
|
||||
attachmentMessage.attachments.map(
|
||||
(a) => uploaded.push(`[${a.filename} (${(a.size / CONSTANTS.IMAGES.MB_DIVIDER).toFixed(2)}mb)](${a.url})`)
|
||||
);
|
||||
@ -395,7 +394,7 @@ class GuildLogger extends Observer {
|
||||
//Unknown webhook -> webhook was deleted, remove it from db so it doesn't make any more unnecessary calls
|
||||
if (err.code === 10015) {
|
||||
wrapper.updateWebhook('messages');
|
||||
} else this.client.logger.error(err.stack);
|
||||
} else this.logger.error(err.stack);
|
||||
return { error: true };
|
||||
});
|
||||
if (result.error) break;
|
||||
@ -411,10 +410,9 @@ class GuildLogger extends Observer {
|
||||
if (oldMessage.embeds.length !== newMessage.embeds.length && oldMessage.content === newMessage.content) return;
|
||||
if (oldMessage.author.bot) return;
|
||||
|
||||
const { guild } = oldMessage;
|
||||
const { guild, guildWrapper: wrapper } = oldMessage;
|
||||
if (!guild) return;
|
||||
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
if (!oldMessage.member) oldMessage.member = await guild.members.fetch(oldMessage.author);
|
||||
const { member, channel, author, reference } = oldMessage;
|
||||
|
||||
@ -454,7 +452,7 @@ class GuildLogger extends Observer {
|
||||
if (img.height && img.width) embed.image = { url: img.url };
|
||||
}
|
||||
|
||||
await hook.send({ embeds: [embed] }).catch(this.client.logger.error);
|
||||
await hook.send({ embeds: [embed] }).catch(this.logger.error);
|
||||
|
||||
} else {
|
||||
|
||||
@ -517,7 +515,7 @@ class GuildLogger extends Observer {
|
||||
//if(newMessage.content.length > 1024) embed.description += '\n' + oldMessage.format('MSGLOG_EDIT_NEW_CUTOFF');
|
||||
|
||||
await hook.send({ embeds: [embed] }).catch((err) => {
|
||||
this.client.logger.error('Error in message edit:\n' + err.stack);
|
||||
this.logger.error('Error in message edit:\n' + err.stack);
|
||||
});
|
||||
|
||||
}
|
||||
@ -527,11 +525,10 @@ class GuildLogger extends Observer {
|
||||
async voiceState(oldState, newState) {
|
||||
|
||||
if (oldState.channel && newState.channel && oldState.channel === newState.channel) return;
|
||||
const { guild, member } = oldState;
|
||||
const { guild, member, guildWrapper: wrapper } = oldState;
|
||||
|
||||
//TODO: add checks for disconnecting bot from vc when left alone in one (music player)
|
||||
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const settings = await wrapper.settings();
|
||||
const setting = settings.voice;
|
||||
if (!setting || !setting.channel) return;
|
||||
@ -582,8 +579,7 @@ class GuildLogger extends Observer {
|
||||
|
||||
async memberJoin(member) {
|
||||
|
||||
const { guild } = member;
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const { guild, guildWrapper: wrapper } = member;
|
||||
const settings = await wrapper.settings();
|
||||
const setting = settings.members;
|
||||
if (!setting.channel) return;
|
||||
@ -602,8 +598,7 @@ class GuildLogger extends Observer {
|
||||
|
||||
async memberLeave(member) {
|
||||
|
||||
const { guild } = member;
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const { guild, guildWrapper: wrapper } = member;
|
||||
const settings = await wrapper.settings();
|
||||
const setting = settings.members;
|
||||
if (!setting.channel) return;
|
||||
@ -624,8 +619,7 @@ class GuildLogger extends Observer {
|
||||
|
||||
if (oldMember.nickname === newMember.nickname) return;
|
||||
|
||||
const { guild, user } = oldMember;
|
||||
const wrapper = new GuildWrapper(this.client, guild);
|
||||
const { guild, user, guildWrapper: wrapper } = oldMember;
|
||||
const settings = await wrapper.settings();
|
||||
const setting = settings.nicknames;
|
||||
if (!setting.channel) return;
|
||||
|
Loading…
Reference in New Issue
Block a user