From 26f8117ae7f94237a05096c46656979a8957d6cc Mon Sep 17 00:00:00 2001 From: "Navy.gif" Date: Sun, 16 Jan 2022 22:30:21 +0200 Subject: [PATCH] setting and filtersetting --- src/structure/interfaces/FilterSetting.js | 208 ++++++++++++++++++++++ src/structure/interfaces/Setting.js | 39 +++- 2 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 src/structure/interfaces/FilterSetting.js diff --git a/src/structure/interfaces/FilterSetting.js b/src/structure/interfaces/FilterSetting.js new file mode 100644 index 0000000..e7bc84e --- /dev/null +++ b/src/structure/interfaces/FilterSetting.js @@ -0,0 +1,208 @@ +const Setting = require("./Setting.js"); +const Util = require('../../Util.js'); + +const validInfractions = ['WARN', 'MUTE', 'KICK', 'BAN', 'SOFTBAN']; + +class FilterSetting extends Setting { + + async _action(interaction, method, actions, { _wordWatcher } = {}) { + + if (!['add', 'remove', 'edit', 'list', 'reset'].includes(method)) + return { error: true, msg: interaction.format('ERR_INVALID_METHOD', { method }) }; + + let result = null, + index = null; + if (method === 'add') { + if (actions.length >= 5 && _wordWatcher) return { + error: true, + msg: interaction.format('SETTING_WORDWATCHER_ACTION_LIMIT') + }; + result = await this._createAction(interaction, actions, { _wordWatcher }); + index = 'SETTING_FILTER_ACTION_ADD'; + } else if (method === 'edit') { + result = await this._editAction(interaction, actions); + index = 'S_FILTER_ACTION_EDIT'; + } else if (method === 'remove') { + result = await this._removeAction(interaction, actions); + index = 'S_FILTER_ACTION_REMOVE'; + } else if (method === 'list') { + this._listActions(interaction, actions); + return; + } else if (method === 'reset') { + result = {}; + actions = []; + index = 'S_FILTER_ACTION_RESET'; + } + + if (result.error) return result; + + //setting.actions.push(result); + //console.log(result); + return { + index, + params: { + type: result.type, + duration: result.duration ? Util.humanise(result.duration) : 'INF', + points: result.points || interaction.format('ON_OFF_TOGGLE', { toggle: false }, { code: true }), + force: interaction.format('ON_OFF_TOGGLE', { toggle: result.force }, { code: true }), + prune: interaction.format('ON_OFF_TOGGLE', { toggle: result.prune }, { code: true }), + trigger: result.trigger instanceof Array ? '||' + result.trigger.join(', ') + '||' : '`' + result.trigger + '`' + } + }; + } + + async _createAction(interaction, actions, { _wordWatcher }) { + + const actionObject = { type: null, duration: null, points: null, expiration: null, force: false, prune: false }; + + const valid = [...validInfractions]; + if (_wordWatcher) valid.push('DELETE'); //Used for wordwatcher quick actions to just delete the flagged message + + let response = await interaction.promptMessage(interaction.format('SETTING_FILTER_ACTION_ADD_START', + { + valid: valid.join('`, `'), + wordwatcher: _wordWatcher ? interaction.format('SETTING_WORDWATCHER_ACTION_ADD_START', { amount: actions.length }) : '' + }), { editInteraction: true }); + if (!response) return { error: true, msg: interaction.format('ERR_TIMEOUT') }; + + const [action] = response.content.toLowerCase().split(' '); + await response.delete(); + if (['cancel', 'abort', 'exit'].includes(action)) return { + error: true, + msg: interaction.format('ERR_CANCEL') + }; + + const { resolver } = this.client; + const infType = resolver.resolveInfraction(action); + if ((!infType + || !validInfractions.includes(infType)) + && !['del', 'delete'].includes(action)) return { + error: true, + msg: interaction.format('SETTING_FILTER_INVALID_INFRACTION', { valid: validInfractions.join('`, `') }) + }; + actionObject.type = infType; + + //Add a duration to the action + if (['MUTE', 'BAN'].includes(infType)) { + + response = await interaction.promptMessage(interaction.format('SETTING_FILTER_ACTION_ADD_TIMER', + { action: infType }), { editInteraction: true }); + if (!response) return { error: true, msg: interaction.format('ERR_TIMEOUT') }; + const content = response.content.toLowerCase(); + await response.delete(); + if (['cancel', 'abort', 'exit'].includes(content)) return { + error: true, + msg: interaction.format('ERR_CANCEL') + }; + + if (!['no', 'n'].includes(content)) { + const time = resolver.resolveTime(content); + if (!time) interaction.channel.send(interaction.format('SETTING_FILTER_ACTION_ADD_TIMER_FAIL')); + else actionObject.duration = time; + } + + } + + const settings = interaction.guild._settings; + //Add points & expiration to action if modpoints are enabled + if (settings.modpoints?.enabled) { + + // Points + response = await interaction.promptMessage(interaction.format('SETTING_FILTER_ACTION_ADD_POINTS'), { editInteraction: true }); + if (!response) return { error: true, msg: interaction.format('ERR_TIMEOUT') }; + const content = response.content.toLowerCase(); + await response.delete(); + if (['cancel', 'abort', 'exit'].includes(content)) return { + error: true, + msg: interaction.format('ERR_CANCEL') + }; + + if (!['no', 'n'].includes(content)) { + + const points = /(\d{1,3})\s?(points?|pts?|p)?/iu; + const match = content.match(points); + if (!match) interaction.channel.send(interaction.format('SETTING_FILTER_ACTION_ADD_POINTS_FAIL')); + else { + let value = parseInt(match[1]); + if (value < 0 || value > 100) { + if (value < 0) value = 0; + else value = 100; + interaction.channel.send(interaction.format('SETTING_FILTER_ACTION_ADD_POINTS_RANGE', { params: { value } })); + } + actionObject.points = value; + } + + } + + // Expiration + if (actionObject.points) { + response = await interaction.promptMessage( + interaction.format('SETTING_FILTER_ACTION_ADD_EXPIRATION'), + { editInteraction: true } + ); + if (!response) return { error: true, msg: interaction.format('ERR_TIMEOUT') }; + const content = response.content.toLowerCase(); + await response.delete(); + if (['cancel', 'abort', 'exit'].includes(content)) return { + error: true, + msg: interaction.format('ERR_CANCEL') + }; + + if (!['no', 'n'].includes(content)) { + + const time = resolver.resolveTime(response.content); + if (!time) interaction.channel.send(interaction.format('SETTING_FILTER_ACTION_ADD_EXPIRATION_FAIL')); + else actionObject.expiration = time; + + } + } + + } + + //Should it force the action if automod is enabled + if (settings.autoModeration?.enabled) { + + response = await interaction.promptMessage(interaction.format('SETTING_FILTER_ACTION_ADD_FORCE'), { editInteraction: true }); + if (!response) return { error: true, msg: interaction.format('ERR_TIMEOUT') }; + const content = response.content.toLowerCase(); + await response.delete(); + if (['cancel', 'abort', 'exit'].includes(content)) return { + error: true, + msg: interaction.format('ERR_CANCEL') + }; + + if (['yes', 'ye', 'y'].includes(content)) { + actionObject.force = true; + } + + } + + //Should the action also prune the user's messages + if (infType !== 'SOFTBAN') { + response = await interaction.promptMessage(interaction.format('SETTING_FILTER_ACTION_ADD_PRUNE'), { editInteraction: true }); + if (!response) return { error: true, msg: interaction.format('ERR_TIMEOUT') }; + const content = response.content.toLowerCase(); + await response.delete(); + if (['cancel', 'abort', 'exit'].includes(content)) return { + error: true, + msg: interaction.format('ERR_CANCEL') + }; + + if (['yes', 'ye', 'y'].includes(content)) { + actionObject.prune = true; + } + } + + //What should trigger the action? + //Implemented in the subclass + const result = await this._createTrigger(interaction, action, actionObject, actions); + if (result && result.error) return result; + + actions.push(actionObject); + return actionObject; + + } + +} + +module.exports = FilterSetting; \ No newline at end of file diff --git a/src/structure/interfaces/Setting.js b/src/structure/interfaces/Setting.js index 4f9c30f..1ac487a 100644 --- a/src/structure/interfaces/Setting.js +++ b/src/structure/interfaces/Setting.js @@ -88,7 +88,11 @@ class Setting extends Component { if (this.commandOptions.length) { fields.push({ name: `》 ${guild.format(`GENERAL_OPTIONS`)}`, - value: this.commandOptions.map((opt) => `**${opt.name} [${opt.type}]:** ${opt.description} ${opt.choices.length ? `\n__${guild.format('GENERAL_CHOICES')}__\n\t${opt.choices.map((choice) => choice.name).join('\n\t')}` : ''}`).join('\n') + value: this.commandOptions.map( + (opt) => `**${opt.name} [${opt.type}]:** ${opt.description} ${opt.choices.length + ? `\n__${guild.format('GENERAL_CHOICES')}__: ${opt.choices.map((choice) => choice.name).join(', ')}` + : ''}` + ).join('\n\n') }); } @@ -96,7 +100,7 @@ class Setting extends Component { author: { name: `${this.display} [module:${this.module.name}]` }, - description: this.description, + description: guild.format(`SETTING_${this.name.toUpperCase()}_HELP`), fields }; @@ -145,6 +149,36 @@ class Setting extends Component { }); } + // Manipulator functions + add(list = [], params = [], caseSensitive = false) { + for (const param of params) { + if (!list.includes(param)) list.push(caseSensitive ? param : param.toLowerCase()); + } + return list; + } + + remove(list = [], params = [], caseSensitive = false) { + for (const param of params) { + if (list.includes(param)) list.splice(list.indexOf(caseSensitive ? param : param.toLowerCase()), 1); + } + return list; + } + + set(list, params = []) { + list = params; + return list; + } + + reset(list) { + list = []; + return list; + } + + edit(list, params) { + + } + + // Functions for message component based settings /** * Abstract components method, should be overridden by the implementing class and called, returns the select menu component. * Exists to reduce copypasting @@ -163,7 +197,6 @@ class Setting extends Component { } ]; } - /** * Generator method to generate a function for quick button styles