From fed630028e5d570d468900e85fe87eaa0e33873e Mon Sep 17 00:00:00 2001 From: Navy Date: Sat, 12 Jun 2021 16:27:39 +0300 Subject: [PATCH 01/15] wordfilter improvements, reduced false positives + whitelist support --- .../client/components/observers/Automoderation.js | 13 +++++++++---- util/filterPresets.json | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/structure/client/components/observers/Automoderation.js b/structure/client/components/observers/Automoderation.js index 8728d89..92c7baf 100644 --- a/structure/client/components/observers/Automoderation.js +++ b/structure/client/components/observers/Automoderation.js @@ -182,12 +182,17 @@ module.exports = class AutoModeration extends Observer { for (const reg of regex) { - const match = content.match(new RegExp(reg, 'iu')); + const match = content.match(new RegExp(`(?:^|\\s)${reg}`, 'iu')); // (?:^|\\s) |un if (match) { - log += `\nMessage matched with "${reg}" in the regex list.\nMatch: ${match[0]}\nFull content: ${content}`; + //log += `\next reg: ${tmp}`; + const fullWord = words.find((word) => word.includes(match[0])); + + if (this.whitelist.find(fullWord) || 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: match[0], + match: fullWord, matched: true, _matcher: match[0].toLowerCase(), matcher: `Regex: __${reg}__`, @@ -310,7 +315,7 @@ module.exports = class AutoModeration extends Observer { for (const reg of words) { - match = content.match(new RegExp(reg, 'iu')); + match = content.match(new RegExp(` ${reg} `, 'iu')); if (match) break; diff --git a/util/filterPresets.json b/util/filterPresets.json index 99f66df..7e82d16 100644 --- a/util/filterPresets.json +++ b/util/filterPresets.json @@ -1,8 +1,7 @@ { "regex": { "slurs": [ - "n(ae|ji|j|y|i|x|!|1|\\||l)(gg?|qq|99?|bb)(?!(ht|el|un))((e|3)r|let|ur|\\s?nog|y|ah?|or)?s?", - "(? Date: Sat, 12 Jun 2021 16:35:34 +0300 Subject: [PATCH 02/15] debug stuff --- structure/client/components/observers/Automoderation.js | 8 +++++++- structure/interfaces/BinaryTree.js | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/structure/client/components/observers/Automoderation.js b/structure/client/components/observers/Automoderation.js index 92c7baf..5d72679 100644 --- a/structure/client/components/observers/Automoderation.js +++ b/structure/client/components/observers/Automoderation.js @@ -188,7 +188,13 @@ module.exports = class AutoModeration extends Observer { //log += `\next reg: ${tmp}`; const fullWord = words.find((word) => word.includes(match[0])); - if (this.whitelist.find(fullWord) || whitelist.some((word) => word === fullWord)) continue; + let inWL = false; + try { // This is for debugging only + inWL = this.whitelist.find(fullWord); + } catch (err) { + this.client.logger.debug(fullWord, match[0], 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 = { diff --git a/structure/interfaces/BinaryTree.js b/structure/interfaces/BinaryTree.js index 464e3f4..47ed616 100644 --- a/structure/interfaces/BinaryTree.js +++ b/structure/interfaces/BinaryTree.js @@ -64,7 +64,7 @@ class BinaryTree { */ find(val) { - val.toLowerCase(); + val = val.toLowerCase(); if(this.isEmpty()) return; From e77f3c6254397a2355e05c087d3210aa08926b19 Mon Sep 17 00:00:00 2001 From: Navy Date: Sat, 12 Jun 2021 16:47:53 +0300 Subject: [PATCH 03/15] wordwatcher tweak --- structure/client/components/observers/Automoderation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/structure/client/components/observers/Automoderation.js b/structure/client/components/observers/Automoderation.js index 5d72679..0680a6c 100644 --- a/structure/client/components/observers/Automoderation.js +++ b/structure/client/components/observers/Automoderation.js @@ -321,7 +321,7 @@ module.exports = class AutoModeration extends Observer { for (const reg of words) { - match = content.match(new RegExp(` ${reg} `, 'iu')); + match = content.match(new RegExp(`(?:^|\\s)${reg}`, 'iu')); if (match) break; @@ -337,7 +337,7 @@ module.exports = class AutoModeration extends Observer { `, // ** User:** <@${ author.id }> color: 15120384, fields: context.reverse().reduce((acc, val) => { - const text = val.content.length ? val.content.replace(match, '**__$&__**') : '**NO CONTENT**'; + const text = val.content.length ? Util.escapeMarkdown(val.content).replace(match, '**__$&__**') : '**NO CONTENT**'; acc.push({ name: `${val.author.tag} (${val.author.id}) - ${val.id}`, value: text.length < 1024 ? text : text.substring(0, 1013) + '...' From b3257ae0d0dbe38e4e2a4d709f1ac53e06ae8f85 Mon Sep 17 00:00:00 2001 From: Navy Date: Sat, 12 Jun 2021 17:35:03 +0300 Subject: [PATCH 04/15] rate limiter tweaks, first message deleted asap --- structure/client/RateLimiter.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/structure/client/RateLimiter.js b/structure/client/RateLimiter.js index ef3e011..77776c1 100644 --- a/structure/client/RateLimiter.js +++ b/structure/client/RateLimiter.js @@ -16,9 +16,10 @@ class RateLimiter { this.deleteTimeouts = {}; //same as above this.lastSend = {}; //used by limitSend + this.lastDelete = {}; this.sendInterval = 7.5; //How frequently sending is allowed in seconds - this.deleteInterval = 1.5; //How frequently delete queues should be executed + this.deleteInterval = 2.5; //How frequently delete queues should be executed } @@ -41,7 +42,8 @@ class RateLimiter { if(!this.deleteQueue[channel.id]) this.deleteQueue[channel.id] = []; this.deleteQueue[channel.id].push({ message, resolve, reject }); - if(!this.deleteTimeouts[channel.id] || this.deleteTimeouts[channel.id]._destroyed) this.deleteTimeouts[channel.id] = setTimeout(this.delete.bind(this), this.deleteInterval*1000, channel); + //if(!this.deleteTimeouts[channel.id] || this.deleteTimeouts[channel.id]._destroyed) this.deleteTimeouts[channel.id] = setTimeout(this.delete.bind(this), this.deleteInterval*1000, channel); + this.delete(channel); }); @@ -56,14 +58,23 @@ class RateLimiter { queue = [...this.deleteQueue[channel.id]], deleteThese = []; - for(const item of queue) { + const lastDelete = this.lastDelete[channel.id]; + const now = Math.floor(Date.now() / 1000); + if (now - lastDelete < this.deleteInterval) { + const timeout = this.deleteTimeouts[channel.id]; + if (!timeout || timeout._destroyed) this.deleteTimeouts[channel.id] = setTimeout(this.delete.bind(this), this.deleteInterval*1000, channel); + return; + } + this.lastDelete[channel.id] = now; + + for(const item of queue) { // Organise into arrays const { message, resolve, reject } = item; if(deleteThese.length <= 100) { deleteThese.push(message); resolves.push(resolve); rejects.push(reject); this.deleteQueue[channel.id].shift(); - } else { + } else { // left over messages go in next batch this.deleteTimeouts[channel.id] = setTimeout(this.delete.bind(this), this.deleteInterval*1000, channel); break; } From 98e7f74f69e801c11ec0b2e6a1521703cb1e4630 Mon Sep 17 00:00:00 2001 From: Navy Date: Sat, 12 Jun 2021 18:55:24 +0300 Subject: [PATCH 05/15] bug with whitelist check --- structure/client/components/observers/Automoderation.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/structure/client/components/observers/Automoderation.js b/structure/client/components/observers/Automoderation.js index 0680a6c..78d7e5d 100644 --- a/structure/client/components/observers/Automoderation.js +++ b/structure/client/components/observers/Automoderation.js @@ -182,11 +182,11 @@ module.exports = class AutoModeration extends Observer { for (const reg of regex) { - const match = content.match(new RegExp(`(?:^|\\s)${reg}`, 'iu')); // (?:^|\\s) |un + const match = content.match(new RegExp(`(?:^|\\s)(${reg})`, 'iu')); // (?:^|\\s) |un if (match) { //log += `\next reg: ${tmp}`; - const fullWord = words.find((word) => word.includes(match[0])); + const fullWord = words.find((word) => word.includes(match[1])); let inWL = false; try { // This is for debugging only @@ -350,7 +350,7 @@ module.exports = class AutoModeration extends Observer { }, []) }; - logChannel.send({ embed }); + const sent = await logChannel.send({ embed }); } From ed9905a238d27bc107410865089267f9f7d4c342 Mon Sep 17 00:00:00 2001 From: Navy Date: Sun, 13 Jun 2021 17:51:47 +0300 Subject: [PATCH 06/15] whitelist entries --- util/filterPresets.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/filterPresets.json b/util/filterPresets.json index 7e82d16..0f4bbb3 100644 --- a/util/filterPresets.json +++ b/util/filterPresets.json @@ -499,6 +499,7 @@ "blobsob", "poggers", "night", + "nightmare", "pingers", "nigeria", "nigel", @@ -560,6 +561,7 @@ "determination", "tenis", "nights", + "nights?", "poin", "alteration", "mock", From 757601c608fa9ae3dd27f5d5cbad71ba195018b7 Mon Sep 17 00:00:00 2001 From: Navy Date: Sun, 13 Jun 2021 17:52:03 +0300 Subject: [PATCH 07/15] fix for avg uptime calc --- structure/client/components/commands/developer/Stats.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structure/client/components/commands/developer/Stats.js b/structure/client/components/commands/developer/Stats.js index ca45879..22cb2f1 100644 --- a/structure/client/components/commands/developer/Stats.js +++ b/structure/client/components/commands/developer/Stats.js @@ -82,7 +82,7 @@ class StatsCommand extends Command { }); return acc; }, {}); - totalValues.uptime = this.client.resolver.timeAgo(Math.floor(totalValues.uptime / 1000), true, true, true); + totalValues.uptime = this.client.resolver.timeAgo(Math.floor(totalValues.uptime/ shard.count / 1000), true, true, true); totalValues.avgMem = Math.floor(totalValues.memory / shard.count); //System information From d4ceb44be90e212ee06f4a27a4dd4d732c455f23 Mon Sep 17 00:00:00 2001 From: Navy Date: Sun, 13 Jun 2021 17:52:22 +0300 Subject: [PATCH 08/15] error handling for missing members --- structure/client/components/observers/GuildLogging.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/structure/client/components/observers/GuildLogging.js b/structure/client/components/observers/GuildLogging.js index 51fb317..18e42c7 100644 --- a/structure/client/components/observers/GuildLogging.js +++ b/structure/client/components/observers/GuildLogging.js @@ -72,7 +72,11 @@ class GuildLogger extends Observer { await message.guild.settings(); - if (!message.member) message.member = await message.guild.members.fetch(message.author.id).catch(); + if (!message.member) try { + message.member = await message.guild.members.fetch(message.author.id); + } catch (_) { + // Member not found, do nothing + } const { messageLog } = message.guild._settings; if(!messageLog.channel) return undefined; From ed4a498fc8c1c4894d964655001e4db8d95ae505 Mon Sep 17 00:00:00 2001 From: Navy Date: Sun, 13 Jun 2021 17:52:41 +0300 Subject: [PATCH 09/15] error handling for action building --- .../client/components/settings/moderation/InviteFilter.js | 5 +++++ .../client/components/settings/moderation/LinkFilter.js | 5 +++++ .../client/components/settings/moderation/MentionFilter.js | 5 +++++ .../client/components/settings/moderation/WordFilter.js | 7 +++++++ 4 files changed, 22 insertions(+) diff --git a/structure/client/components/settings/moderation/InviteFilter.js b/structure/client/components/settings/moderation/InviteFilter.js index e68593a..11dddcd 100644 --- a/structure/client/components/settings/moderation/InviteFilter.js +++ b/structure/client/components/settings/moderation/InviteFilter.js @@ -120,6 +120,11 @@ module.exports = class InviteFilter extends FilterSetting { } + if (langParams.error) return { + error: true, + msg: langParams.msg + }; + await message.guild._updateSettings({ [this.index]: setting }); return { error: false, diff --git a/structure/client/components/settings/moderation/LinkFilter.js b/structure/client/components/settings/moderation/LinkFilter.js index 0d04b72..218424c 100644 --- a/structure/client/components/settings/moderation/LinkFilter.js +++ b/structure/client/components/settings/moderation/LinkFilter.js @@ -202,6 +202,11 @@ module.exports = class LinkFilter extends FilterSetting { msg: message.format('ERR_INVALID_METHOD', { method }) }; + if (langParams.error) return { + error: true, + msg: langParams.msg + }; + await message.guild._updateSettings({ [this.index]: setting }); return { error: false, diff --git a/structure/client/components/settings/moderation/MentionFilter.js b/structure/client/components/settings/moderation/MentionFilter.js index 2170c62..9912535 100644 --- a/structure/client/components/settings/moderation/MentionFilter.js +++ b/structure/client/components/settings/moderation/MentionFilter.js @@ -149,6 +149,11 @@ module.exports = class MentionFilter extends FilterSetting { msg: message.format('ERR_INVALID_METHOD', { method }) }; + if (langParams.error) return { + error: true, + msg: langParams.msg + }; + await message.guild._updateSettings({ [this.index]: setting }); return { error: false, diff --git a/structure/client/components/settings/moderation/WordFilter.js b/structure/client/components/settings/moderation/WordFilter.js index f6ebc19..8580260 100644 --- a/structure/client/components/settings/moderation/WordFilter.js +++ b/structure/client/components/settings/moderation/WordFilter.js @@ -53,6 +53,7 @@ module.exports = class WordFilter extends FilterSetting { async handle(message, params) { + // eslint-disable-next-line prefer-const let [method, ...args] = params; method = method.toLowerCase(); @@ -254,6 +255,11 @@ module.exports = class WordFilter extends FilterSetting { }; } + if (langParams.error) return { + error: true, + msg: langParams.msg + }; + await message.guild._updateSettings({ [this.index]: setting }); return { error: false, @@ -263,6 +269,7 @@ module.exports = class WordFilter extends FilterSetting { } async _createTrigger(message, action, actionObject, setting) { + const response = await message.prompt(message.format('S_WORDFILTER_ACTION_ADD_TRIGGERS'), { time: 60 * 1000 }); if (!response) { if (setting.actions.find((ac) => ac.trigger === 'generic')) return { From b9db9e759c7306f9af6b2a4ac854b98054429aea Mon Sep 17 00:00:00 2001 From: Navy Date: Tue, 15 Jun 2021 13:04:38 +0300 Subject: [PATCH 10/15] emoji resolver --- package.json | 1 + structure/client/Resolver.js | 64 ++++++++++++++++++++++++++++++++++-- yarn.lock | 7 +++- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 330f3c6..91288d8 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "request": "^2.88.2", "similarity": "^1.2.1", "timestring": "^6.0.0", + "twemoji-parser": "^13.1.0", "winston": "^3.2.1", "winston-transport": "^4.3.0" }, diff --git a/structure/client/Resolver.js b/structure/client/Resolver.js index 8c5e9c7..a3a8b76 100644 --- a/structure/client/Resolver.js +++ b/structure/client/Resolver.js @@ -1,6 +1,7 @@ const timestring = require('timestring'); const moment = require('moment'); const dns = require('dns'); +const { parse: resolveTwemoji } = require('twemoji-parser'); const { InfractionResolves } = require('../../util/Constants.js'); // eslint-disable-next-line no-unused-vars @@ -593,9 +594,9 @@ class Resolver { const { roles } = guild; const resolved = []; - for(const resolveable of resolveables) { + const id = /^(<@&)?([0-9]{16,22})>?/iu; - const id = /^(<@&)?([0-9]{16,22})>?/iu; + for(const resolveable of resolveables) { if(id.test(resolveable)) { @@ -710,6 +711,65 @@ class Resolver { return { parsed, parameters }; } + + async resolveEmojis(resolveables = [], strict, guild) { + + if (typeof resolveables === 'string') resolveables = [resolveables]; + if (resolveables.length === 0) return false; + //const { emojis: guildEmojis } = guild; + const { emojis: clientEmojis } = this.client; + const resolved = []; + + const emojiMention = /<(?:a)?:?([\w-]{2,32}):(\d{17,32})>/iu; + + for (const resolveable of resolveables) { + + if (emojiMention.test(resolveable)) { + + const match = resolveable.match(emojiMention); + const [, , eId] = match; + + const emoji = clientEmojis.resolve(eId); //.catch(this.client.logger.error); // use .fetch(eId) once v13 rolls out + + if (emoji) resolved.push({ type: 'custom', emoji }); + + } else { + + const sorter = (a, b) => a.name.length - b.name.length; + const filter = (e) => { + if (!strict) return e.name.toLowerCase().includes(resolveable.toLowerCase()); + return e.name.toLowerCase() === resolveable.toLowerCase(); + }; + let emoji = null; + if (guild) emoji = guild.emojis.cache.sort(sorter).filter(filter).first(); + if (!emoji) emoji = clientEmojis.cache.sort(sorter).filter(filter).first(); + if (emoji) { + resolved.push({ type: 'custom', emoji }); + continue; + } else { // twemoji parse + const [result] = resolveTwemoji(resolveable); + if (result) { + ({ text: emoji } = result); + resolved.push({ type: 'unicode', emoji }); + } + } + + } + + } + + return resolved.length > 0 ? resolved : false; + + } + + async resolveEmoji(resolveable, strict, guild) { + + if (!resolveable) return false; + if (resolveable instanceof Array) throw new Error('Resolveable cannot be of type Array, use resolveEmojis for resolving arrays of emojis'); + const result = await this.resolveEmojis([resolveable], strict, guild); + return result ? result[0] : false; + + } } diff --git a/yarn.lock b/yarn.lock index 40615da..9e391a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1572,7 +1572,7 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -node-fetch@^2.6.0, node-fetch@^2.6.1: +node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== @@ -2247,6 +2247,11 @@ tweetnacl@^1.0.3: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== +twemoji-parser@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-13.1.0.tgz#65e7e449c59258791b22ac0b37077349127e3ea4" + integrity sha512-AQOzLJpYlpWMy8n+0ATyKKZzWlZBJN+G0C+5lhX7Ftc2PeEVdUU/7ns2Pn2vVje26AIZ/OHwFoUbdv6YYD/wGg== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" From 97bf057503a1c5d8a7726e0c0228931973474cfb Mon Sep 17 00:00:00 2001 From: Navy Date: Tue, 15 Jun 2021 13:05:19 +0300 Subject: [PATCH 11/15] word filter stuff --- .../languages/en_us/en_us_settings.lang | 19 +++++++++++++++++++ util/filterPresets.json | 1 + 2 files changed, 20 insertions(+) diff --git a/structure/language/languages/en_us/en_us_settings.lang b/structure/language/languages/en_us/en_us_settings.lang index 996d5b6..77ccd07 100644 --- a/structure/language/languages/en_us/en_us_settings.lang +++ b/structure/language/languages/en_us/en_us_settings.lang @@ -52,6 +52,8 @@ Can be one of `{valid}`. > You can cancel this series of prompts by responding with `cancel`. +{wordwatcher} + [S_FILTER_ACTION_ADD_TIMER] Would you like the **{action}** to have a timer? Not assigning a timer will use defaults for the corresponding action. @@ -219,6 +221,11 @@ Successfully removed all presets from the regex filter. [S_WORDWATCHER_DESCRIPTION] Configure the behaviour of the word watcher. +Wordwatcher is a moderation utility that flags messages for manual review based on keywords. +Keywords can be regex expressions. + +Wordwatcher also supports having 5 reactions for quick actions. + [S_WORDWATCHER_TOGGLE] Successfully toggled the word watcher **{toggle}**. @@ -261,6 +268,18 @@ Successfully removed **{changes}** from the watch list. [S_WORDWATCHER_CHANNEL] Will log flagged messages to <#{channel}>. +[S_WORDWATCHER_ACTION_LIMIT] +You've hit the limit of quick actions. Either modify or remove existing ones. + +[S_WORDWATCHER_ACTION_ADD_START] +You can only define up to 5 quick actions, you currently have {amount} existing actions. + +[S_WORDWATCHER_ACTION_ADD_TRIGGERS] +Which emoji should represent this action? +Make sure it is one that the bot has access to (i.e. from this server or one you know the bot is in). + +The bot will use defaults if no emoji is given. + // Wordfilter [S_WORDFILTER_DESCRIPTION] Configure the word filtering behaviour for your server. diff --git a/util/filterPresets.json b/util/filterPresets.json index 0f4bbb3..0b1f47a 100644 --- a/util/filterPresets.json +++ b/util/filterPresets.json @@ -500,6 +500,7 @@ "poggers", "night", "nightmare", + "nightcore", "pingers", "nigeria", "nigel", From 68f2fef16ef97e44088029dbaa03d41af4815572 Mon Sep 17 00:00:00 2001 From: Navy Date: Tue, 15 Jun 2021 20:15:55 +0300 Subject: [PATCH 12/15] should not respond in ignored channel even for inhibitor errors --- structure/client/Resolver.js | 9 +++++++++ .../client/components/observers/CommandHandler.js | 13 +++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/structure/client/Resolver.js b/structure/client/Resolver.js index a3a8b76..d98cf2a 100644 --- a/structure/client/Resolver.js +++ b/structure/client/Resolver.js @@ -712,6 +712,15 @@ class Resolver { } + /** + * Resolves input into an emoji, either a custom or a unicode emoji. Returned object will have a type property indicating whether it's custom or unicode. + * + * @param {Array} [resolveables=[]] + * @param {boolean} strict + * @param {Guild} guild + * @return {Object} + * @memberof Resolver + */ async resolveEmojis(resolveables = [], strict, guild) { if (typeof resolveables === 'string') resolveables = [resolveables]; diff --git a/structure/client/components/observers/CommandHandler.js b/structure/client/components/observers/CommandHandler.js index 7edbdaa..915c0a5 100644 --- a/structure/client/components/observers/CommandHandler.js +++ b/structure/client/components/observers/CommandHandler.js @@ -389,15 +389,16 @@ class CommandHandler extends Observer { const silent = inhibitors.filter((i) => i.inhibitor.silent); const nonsilent = inhibitors.filter((i) => !i.inhibitor.silent); - if(nonsilent.length === 0 && silent.length > 0) return undefined; - if(nonsilent.length > 0) return this.handleError(message, { type: 'inhibitor', ...nonsilent[0] }); + if (silent.length && silent.some((result) => result.inhibitor.id === 'channelIgnore')) return; + if (nonsilent.length === 0 && silent.length > 0) return undefined; + if (nonsilent.length > 0) return this.handleError(message, { type: 'inhibitor', ...nonsilent[0] }); const resolved = await message.resolve(); - if(resolved.error) { + if (resolved.error) { this.client.logger.error(`Command Error | ${message.command.resolveable} | Message ID: ${message.id}\n${resolved.message.stack || resolved.message}`); - if(resolved.message.code === 50013) { + if (resolved.message.code === 50013) { const missing = message.channel.permissionsFor(message.guild.me).missing(['EMBED_LINKS']); - if(missing.length > 0) { + if (missing.length > 0) { return message.respond(message.format('COMMANDHANDLER_COMMAND_MISSINGPERMISSIONS'), { emoji: 'failure' }); @@ -428,7 +429,7 @@ class CommandHandler extends Observer { const reasons = (await Promise.all(promises)).filter((p) => p.error); // Filters out inhibitors with only errors. if(reasons.length === 0) return []; - reasons.sort((a, b) => b.inhibitor.priority - a.inhibitor.priority); // Sorts inhibitor errors by most important. + reasons.sort((a, b) => a.inhibitor.priority - b.inhibitor.priority); // Sorts inhibitor errors by most important. return reasons; } From 1d499560a1b457183f444875f5ee4622c3d6e9b1 Mon Sep 17 00:00:00 2001 From: Navy Date: Tue, 15 Jun 2021 23:24:56 +0300 Subject: [PATCH 13/15] Added a field to indicate a message was a reply --- .../components/observers/GuildLogging.js | 56 ++++++++++++------- .../languages/en_us/en_us_observers.lang | 7 +++ util/filterPresets.json | 1 + 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/structure/client/components/observers/GuildLogging.js b/structure/client/components/observers/GuildLogging.js index 18e42c7..7a285df 100644 --- a/structure/client/components/observers/GuildLogging.js +++ b/structure/client/components/observers/GuildLogging.js @@ -103,30 +103,42 @@ class GuildLogger extends Observer { return; } + const { reference, channel, author, content, id } = message; + const embed = { // author: { // name: message.format('MSGLOG_DELETE_TITLE', { channel: message.channel.name, author: Util.escapeMarkdown(message.author.tag) }), //`${message.author.tag} (${message.author.id})`, // icon_url: message.author.displayAvatarURL({ size: 32 }) //eslint-disable-line camelcase // }, - title: message.format('MSGLOG_DELETE_TITLE', { channel: message.channel.name, author: Util.escapeMarkdown(message.author.tag) }), - description: Util.escapeMarkdown(message.content)?.replace(/\\n/gu, ' ') || message.format('MSGLOG_NOCONTENT'), + title: message.format('MSGLOG_DELETE_TITLE', { channel: channel.name, author: Util.escapeMarkdown(author.tag) }), + description: Util.escapeMarkdown(content)?.replace(/\\n/gu, ' ') || message.format('MSGLOG_NOCONTENT'), color: CONSTANTS.COLORS.RED, footer: { - text: message.format('MSGLOG_DELETE_FOOTER', { msgID: message.id, userID: message.author.id }) + text: message.format('MSGLOG_DELETE_FOOTER', { msgID: id, userID: author.id }) }, - timestamp: message.createdAt + timestamp: message.createdAt, + fields: [] }; + + if (reference && reference.channelID === channel.id) { + const referenced = await channel.messages.fetch(reference.messageID); + embed.fields.push({ + name: message.format('MSGLOG_REPLY', { tag: referenced.author.tag, id: referenced.author.id }), + value: message.format('MSGLOG_REPLY_VALUE', { + content: referenced.content.length > 900 ? referenced.content.substring(0, 900) + '...' : referenced.content, + link: referenced.url + }) + }); + } if (message.filtered) { - embed.fields = [ - { - name: message.format('MSGLOG_FILTERED'), - value: stripIndents` + embed.fields.push({ + name: message.format('MSGLOG_FILTERED'), + value: stripIndents` ${message.format(message.filtered.preset ? 'MSGLOG_FILTERED_PRESET' : 'MSGLOG_FILTERED_VALUE', { ...message.filtered })} ${message.filtered.sanctioned ? message.format('MSGLOG_FILTERED_SANCTIONED') : ''} `// + () - } - ]; + }); } const uploadedFiles = []; @@ -341,7 +353,7 @@ class GuildLogger extends Observer { if (!guild) return; if (!oldMessage.member) oldMessage.member = await guild.members.fetch(oldMessage.author); - const { member, channel, author } = oldMessage; + const { member, channel, author, reference } = oldMessage; const settings = await guild.settings(); const chatlogs = settings.messageLog; @@ -390,16 +402,7 @@ class GuildLogger extends Observer { description: oldMessage.format('MSGLOG_EDIT_JUMP', { guild: guild.id, channel: channel.id, message: oldMessage.id }), color: CONSTANTS.COLORS.YELLOW, timestamp: oldMessage.createdAt, - fields: [ - // { - // name: oldMessage.format('MSGLOG_EDIT_OLD'), - // value: oldMessage.content.length > 1024 ? oldMessage.content.substring(0, 1021) + '...' : oldMessage.content - // }, - // { - // name: oldMessage.format('MSGLOG_EDIT_NEW'), - // value: newMessage.content.length > 1024 ? newMessage.content.substring(0, 1021) + '...' : newMessage.content - // } - ] + fields: [ ] }; const oldCon = oldMessage.content, @@ -423,6 +426,17 @@ class GuildLogger extends Observer { name: '\u200b', value: '...' + newCon.substring(1021) }); + + if (reference && reference.channelID === channel.id) { + const referenced = await channel.messages.fetch(reference.messageID); + embed.fields.push({ + name: oldMessage.format('MSGLOG_REPLY', { tag: referenced.author.tag, id: referenced.author.id }), + value: oldMessage.format('MSGLOG_REPLY_VALUE', { + content: referenced.content.length > 900 ? referenced.content.substring(0, 900) + '...' : referenced.content, + link: referenced.url + }) + }); + } //if(oldMessage.content.length > 1024) embed.description += '\n' + oldMessage.format('MSGLOG_EDIT_OLD_CUTOFF'); //if(newMessage.content.length > 1024) embed.description += '\n' + oldMessage.format('MSGLOG_EDIT_NEW_CUTOFF'); diff --git a/structure/language/languages/en_us/en_us_observers.lang b/structure/language/languages/en_us/en_us_observers.lang index d7bee7a..c18f02c 100644 --- a/structure/language/languages/en_us/en_us_observers.lang +++ b/structure/language/languages/en_us/en_us_observers.lang @@ -72,6 +72,13 @@ Link filter violation. [MSGLOG_NOCONTENT] **__NO TEXT CONTENT__** +[MSGLOG_REPLY] +Message was in reply to user {tag} ({id}): + +[MSGLOG_REPLY_VALUE] +**[Jump to message]({link})** +{content} + [MSGLOG_FILTERED] The message was filtered: diff --git a/util/filterPresets.json b/util/filterPresets.json index 0b1f47a..2761c65 100644 --- a/util/filterPresets.json +++ b/util/filterPresets.json @@ -500,6 +500,7 @@ "poggers", "night", "nightmare", + "nightmares", "nightcore", "pingers", "nigeria", From fb061703801fc6d87950ae5b21d22a9b4301fdf5 Mon Sep 17 00:00:00 2001 From: Navy Date: Tue, 15 Jun 2021 23:30:59 +0300 Subject: [PATCH 14/15] fixed a thing --- structure/client/components/observers/GuildLogging.js | 4 +++- structure/language/languages/en_us/en_us_observers.lang | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/structure/client/components/observers/GuildLogging.js b/structure/client/components/observers/GuildLogging.js index 7a285df..8397ab6 100644 --- a/structure/client/components/observers/GuildLogging.js +++ b/structure/client/components/observers/GuildLogging.js @@ -429,10 +429,12 @@ class GuildLogger extends Observer { if (reference && reference.channelID === channel.id) { const referenced = await channel.messages.fetch(reference.messageID); + // eslint-disable-next-line no-nested-ternary + const content = referenced.content ? referenced.content.length > 900 ? referenced.content.substring(0, 900) + '...' : referenced.content : oldMessage.format('MSGLOG_REPLY_NOCONTENT'); embed.fields.push({ name: oldMessage.format('MSGLOG_REPLY', { tag: referenced.author.tag, id: referenced.author.id }), value: oldMessage.format('MSGLOG_REPLY_VALUE', { - content: referenced.content.length > 900 ? referenced.content.substring(0, 900) + '...' : referenced.content, + content, link: referenced.url }) }); diff --git a/structure/language/languages/en_us/en_us_observers.lang b/structure/language/languages/en_us/en_us_observers.lang index c18f02c..b01743a 100644 --- a/structure/language/languages/en_us/en_us_observers.lang +++ b/structure/language/languages/en_us/en_us_observers.lang @@ -79,6 +79,9 @@ Message was in reply to user {tag} ({id}): **[Jump to message]({link})** {content} +[MSGLOG_REPLY_NOCONTENT] +**__Missing content.__** + [MSGLOG_FILTERED] The message was filtered: From 5870b687124ccf91409cb02541b905b8b71ade88 Mon Sep 17 00:00:00 2001 From: Navy Date: Tue, 15 Jun 2021 23:46:50 +0300 Subject: [PATCH 15/15] regex tweak + promise catching --- structure/client/components/observers/Automoderation.js | 8 +++++--- structure/client/components/observers/GuildLogging.js | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/structure/client/components/observers/Automoderation.js b/structure/client/components/observers/Automoderation.js index 78d7e5d..2048cf2 100644 --- a/structure/client/components/observers/Automoderation.js +++ b/structure/client/components/observers/Automoderation.js @@ -321,7 +321,7 @@ module.exports = class AutoModeration extends Observer { for (const reg of words) { - match = content.match(new RegExp(`(?:^|\\s)${reg}`, 'iu')); + match = content.match(new RegExp(`(?:^|\\s)(${reg})`, 'iu')); if (match) break; @@ -337,7 +337,7 @@ module.exports = class AutoModeration extends Observer { `, // ** User:** <@${ author.id }> color: 15120384, fields: context.reverse().reduce((acc, val) => { - const text = val.content.length ? Util.escapeMarkdown(val.content).replace(match, '**__$&__**') : '**NO CONTENT**'; + 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) + '...' @@ -350,7 +350,9 @@ module.exports = class AutoModeration extends Observer { }, []) }; - const sent = await logChannel.send({ embed }); + const sent = await logChannel.send({ embed }).catch((err) => { + this.client.logger.error('Error in message flag:\n' + err.stack); + }); } diff --git a/structure/client/components/observers/GuildLogging.js b/structure/client/components/observers/GuildLogging.js index 8397ab6..59c258e 100644 --- a/structure/client/components/observers/GuildLogging.js +++ b/structure/client/components/observers/GuildLogging.js @@ -219,7 +219,9 @@ class GuildLogger extends Observer { } - hook.send({ embeds: [embed], files: uploadedFiles }); + await hook.send({ embeds: [embed], files: uploadedFiles }).catch((err) => { + this.client.logger.error('Error in message delete:\n' + err.stack); + }); /* if(message.attachments.size > 0) {