diff --git a/options.json b/options.json index 0ff145d..2158201 100644 --- a/options.json +++ b/options.json @@ -37,7 +37,8 @@ "attachments", "permissions", "webhooks", - "wordwatcher" + "wordwatcher", + "users" ] }, "mariadb": { diff --git a/src/structure/DiscordClient.js b/src/structure/DiscordClient.js index 17b53d1..f9f7613 100644 --- a/src/structure/DiscordClient.js +++ b/src/structure/DiscordClient.js @@ -82,8 +82,8 @@ class DiscordClient extends Client { //Initialize components, localization, and observers. await this.localeLoader.loadLanguages(); - await this.storageManager.initialize(); + await this.moderationManager.initialize(); await this.registry.loadComponents('components/inhibitors', Inhibitor); await this.registry.loadComponents('components/observers', Observer); @@ -97,8 +97,9 @@ class DiscordClient extends Client { this.logger.info(`Built client in ${Date.now()-beforeTime}ms.`); + const ready = this.ready(); await super.login(); - await this.ready(); + await ready; return this; diff --git a/src/structure/client/ModerationManager.js b/src/structure/client/ModerationManager.js index 3b20bd9..89afcf5 100644 --- a/src/structure/client/ModerationManager.js +++ b/src/structure/client/ModerationManager.js @@ -61,7 +61,7 @@ class ModerationManager { //TODO: Load infractions for non-cached guilds... this.client.storageManager.mongodb.infractions.find({ duration: { $gt: 0 }, - guild: { $in: this.client.guilds.cache.keyArray() }, + guild: { $in: this.client.guilds.cache.map((g) => g.id) }, _callbacked: false }).then((results) => { this.logger.info(`Filtering ${results.length} infractions for callback.`); @@ -222,6 +222,15 @@ class ModerationManager { } + /** + * + * + * @param {class} Infraction + * @param {User | GuildMember} target + * @param {object} info + * @return {Infraction} + * @memberof ModerationManager + */ async _handleTarget(Infraction, target, info) { // wrapper: guildWrapper @@ -287,7 +296,7 @@ class ModerationManager { }; const infraction = new Infraction(this.client, { - target: targetWrapper, + target, type, interaction: info.interaction || null, arguments: info.arguments, @@ -308,7 +317,7 @@ class ModerationManager { if (Constant.Hierarchy[infraction.type] <= Constant.Hierarchy[response.escalation.type]) { const escalationClass = Constant.Infractions[response.escalation.type]; const escalationInfraction = new escalationClass(this.client, { - target: targetWrapper, + target, message: info.message || null, arguments: info.arguments, type: escalationClass.type, @@ -363,7 +372,7 @@ class ModerationManager { if (!undoClass) return false; const guild = this.client.guilds.resolve(i.guild); - await guild.settings(); //just incase + //await guild.settings(); //just incase let target = null; if (i.targetType === 'USER') { diff --git a/src/structure/client/wrappers/InteractionWrapper.js b/src/structure/client/wrappers/InteractionWrapper.js index f430705..74b3283 100644 --- a/src/structure/client/wrappers/InteractionWrapper.js +++ b/src/structure/client/wrappers/InteractionWrapper.js @@ -89,12 +89,16 @@ class InteractionWrapper { if (opts.reply) str = `<@!${this.author.id}> ${str}`; } - if (opts.editInteraction) await this.editReply(str); - else await this.channel.send(str, { - files: opts.files, embeds: [opts.embed], + const data = { + content: str, + files: opts.files, + embeds: opts.embed ? [opts.embed] : [], disableMentions: opts.disableMentions - }).then((msg) => { - if (opts.delete) msg.delete(); + }; + + if (opts.editInteraction) await this.editReply(data); + else await this.channel.send(data).then((msg) => { + if (opts.delete) msg.delete(); }); return this.channel.awaitMessages({ diff --git a/src/structure/components/infractions/Mute.js b/src/structure/components/infractions/Mute.js index 00b2305..fe7d27e 100644 --- a/src/structure/components/infractions/Mute.js +++ b/src/structure/components/infractions/Mute.js @@ -45,6 +45,7 @@ class MuteInfraction extends Infraction { try { this.member.roles.add(role, this._reason); } catch (e) { + this.client.logger.debug(`Mute fail, type 1:\n${e.stack}`); return this._fail('C_MUTE_1FAIL'); } break; @@ -107,7 +108,7 @@ class MuteInfraction extends Infraction { const role = await this.client.resolver.resolveRole(this.guild._settings.mute.role, true, this.guild); if (!role) { - this.guild._updateSettings({ + this.guild.updateSettings({ mute: { ...this.guild._settings.mute, role: null diff --git a/src/structure/components/observers/Automoderation.js b/src/structure/components/observers/Automoderation.js index 7ea5d39..ac10fae 100644 --- a/src/structure/components/observers/Automoderation.js +++ b/src/structure/components/observers/Automoderation.js @@ -75,6 +75,8 @@ module.exports = class AutoModeration extends Observer { if (this.executing[filterResult.filter].includes(member.id)) return; this.executing[filterResult.filter].push(member.id); + // Setting this true initially and negate if it fails, otherwise it won't show up as sanctioned in the msg logs + filterResult.sanctioned = true; const InfractionClass = CONSTANTS.Infractions[action.type]; const result = await this.client.moderationManager.handleAutomod(InfractionClass, member, { wrapper, @@ -262,7 +264,7 @@ module.exports = class AutoModeration extends Observer { //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(() => { /**/ }); + res.delete?.().catch(() => { /**/ }); }, 10000); } this.client.rateLimiter.queueDelete(msg.channel, msg).catch(catcher(269)); @@ -515,7 +517,7 @@ module.exports = class AutoModeration extends Observer { //const res = await msg.formattedRespond(`L_FILTER_DELETE`, { params: { user: author.id } }); //if (res) res.delete({ timeout: 10000 }); setTimeout(() => { - res.delete().catch(() => { /**/ }); + res.delete?.().catch(() => { /**/ }); }, 10000); } @@ -581,7 +583,7 @@ module.exports = class AutoModeration extends Observer { 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(() => { /**/ }); + res.delete?.().catch(() => { /**/ }); }, 10000); } // msg.filtered.sactioned = true; @@ -623,7 +625,7 @@ module.exports = class AutoModeration extends Observer { if (!silent) { const res = await this.client.rateLimiter.limitSend(channel, wrapper.format('M_FILTER_DELETE', { user: author.id }), undefined, 'mentionFilter'); setTimeout(() => { - res.delete().catch(() => { /**/ }); + res.delete?.().catch(() => { /**/ }); }, 10000); } diff --git a/src/structure/components/observers/GuildLogging.js b/src/structure/components/observers/GuildLogging.js index 838f678..2dea1ed 100644 --- a/src/structure/components/observers/GuildLogging.js +++ b/src/structure/components/observers/GuildLogging.js @@ -442,7 +442,7 @@ class GuildLogger extends Observer { { author: Util.escapeMarkdown(author.tag), channel: channel.name, - pinned: wrapper.format('PIN_TOGGLE', { toggle: newMessage.pinned }, true) + pinned: wrapper.format('PIN_TOGGLE', { toggle: newMessage.pinned }, { code: true }) }), description: wrapper.format('MSGLOG_EDIT_JUMP', { guild: guild.id, channel: channel.id, message: oldMessage.id }), color: CONSTANTS.COLORS.LIGHT_BLUE diff --git a/src/structure/components/settings/moderation/AutoModeration.js b/src/structure/components/settings/moderation/AutoModeration.js index 59795ad..7933675 100644 --- a/src/structure/components/settings/moderation/AutoModeration.js +++ b/src/structure/components/settings/moderation/AutoModeration.js @@ -82,9 +82,9 @@ class Automod extends Setting { if (useprevious) setting.usePrevious = useprevious.value; if (threshold) { // TODO: Flesh this out more - if (!setting.threshold[threshold.value]) setting.threshold[threshold.value] = {}; - if (infraction) setting.threshold[threshold.value].type = infraction.value; - if (length) setting.threshold[threshold.value].length = length.value; + if (!setting.thresholds[threshold.value]) setting.thresholds[threshold.value] = {}; + if (infraction) setting.thresholds[threshold.value].type = infraction.value; + if (length) setting.thresholds[threshold.value].length = length.value; } return { index: 'SETTING_SUCCESS_ALT' }; diff --git a/src/structure/interfaces/FilterSetting.js b/src/structure/interfaces/FilterSetting.js index cb36512..8f87ec8 100644 --- a/src/structure/interfaces/FilterSetting.js +++ b/src/structure/interfaces/FilterSetting.js @@ -141,7 +141,7 @@ class FilterSetting extends Setting { } //Should it force the action if automod is enabled - if (settings.autoModeration?.enabled) { + if (settings.automod?.enabled) { const content = await this._prompt(interaction, { index: 'SETTING_FILTER_ACTION_ADD_FORCE' }); if (content.error) return content; @@ -195,7 +195,7 @@ class FilterSetting extends Setting { if (!actions.length) return { error: true, message: interaction.format('SETTING_FILTER_ACTION_REMOVE_NO_ACTIONS') }; const embed = this._createActionEmbed(interaction, actions); - const content = await this._prompt(interaction, { index: 'SETTING_FILTER_ACTION_REMOVE_START', time: 60, embeds: [embed] }); + const content = await this._prompt(interaction, { index: 'SETTING_FILTER_ACTION_REMOVE_START', time: 60, embed }); if (content.error) return content; if (['cancel', 'abort', 'exit'].includes(content)) return { @@ -224,10 +224,14 @@ class FilterSetting extends Setting { const action = actions[index]; //Which property do you want to edit? - const prop = await this._prompt(interaction, { index: 'SETTING_FILTER_ACTION_EDIT_SELECT' }); - if (content.error) return content; - const properties = Object.keys(action); + const prop = await this._prompt(interaction, { + index: 'SETTING_FILTER_ACTION_EDIT_SELECT', + params: { properties: properties.join('`, `') }, + embed: null + }); + if (prop.error) return prop; + if (!properties.includes(prop)) return { error: true, message: interaction.format('SETTING_FILTER_ACTION_EDIT_BADPROP') @@ -244,7 +248,7 @@ class FilterSetting extends Setting { async _editExpiration(interaction, actions, action) { - if (!interaction.guild._settings.moderationPoints?.enabled) return { + if (!interaction.guild._settings.modpoints?.enabled) return { error: true, message: interaction.format('SETTING_FILTER_ACTION_EDIT_POINTS_DISABLED') }; @@ -279,7 +283,7 @@ class FilterSetting extends Setting { async _editPoints(interaction, actions, action) { - if (!interaction.guild._settings.moderationPoints?.enabled) return { + if (!interaction.guild._settings.modpoints?.enabled) return { error: true, message: interaction.format('SETTING_FILTER_ACTION_EDIT_POINTS_DISABLED') }; diff --git a/src/structure/interfaces/Infraction.js b/src/structure/interfaces/Infraction.js index a6d2db4..1883d4f 100644 --- a/src/structure/interfaces/Infraction.js +++ b/src/structure/interfaces/Infraction.js @@ -205,7 +205,7 @@ class Infraction { executor: this.executorId, executorTag: this.executor.display, target: this.targetId, - targetTag: this.target.display, + targetTag: this.target.display || this.target.username || this.target.name, targetType: this.targetType, type: this.type, case: this.case, diff --git a/src/structure/interfaces/Setting.js b/src/structure/interfaces/Setting.js index 4884f57..6434df0 100644 --- a/src/structure/interfaces/Setting.js +++ b/src/structure/interfaces/Setting.js @@ -171,12 +171,12 @@ class Setting extends Component { } // Helper function for prompting for user response by editing the interaction response - async _prompt(interaction, { message= '', params = {}, embeds = [], index, time = 120 }) { + async _prompt(interaction, { message= '', params = {}, embed, index, time = 120 }) { - if (!message.length && !index && !embeds.length) throw new Error('Must declare either message, index or embeds'); + if (!message.length && !index && !embed) throw new Error('Must declare either message, index or embeds'); const response = await interaction.promptMessage( index ? interaction.format(index, params) : message, - { time, editInteraction: true, embeds } + { time, editInteraction: true, embed } ); if (!response) return { error: true, message: interaction.format('ERR_TIMEOUT') };