2020-09-27 20:14:01 +02:00
|
|
|
const Setting = require('./Setting.js');
|
|
|
|
const validInfractions = ['WARN', 'MUTE', 'KICK', 'BAN', 'SOFTBAN'];
|
|
|
|
|
|
|
|
module.exports = class FilterSetting extends Setting {
|
|
|
|
|
|
|
|
async _createAction(message, setting) {
|
|
|
|
|
2020-09-30 23:02:03 +02:00
|
|
|
const actionObject = { action: null, duration: null, points: null, expiration: null, force: false, prune: false };
|
2020-09-27 20:14:01 +02:00
|
|
|
|
|
|
|
let response = await message.prompt(message.format('S_FILTER_ACTION_ADD_START', { valid: validInfractions.join('`, `') }));
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
|
|
|
|
const { resolver } = this.client;
|
|
|
|
const [action] = response.content.split(' ');
|
|
|
|
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(action.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
const infType = resolver.resolveInfraction(action);
|
|
|
|
if (!infType || !validInfractions.includes(infType)) return { error: true, msg: message.format('S_FILTER_INVALID_INFRACTION', { valid: validInfractions.join('`, `') }) };
|
2020-09-30 23:02:03 +02:00
|
|
|
actionObject.type = infType;
|
2020-09-27 20:14:01 +02:00
|
|
|
|
|
|
|
//Add a duration to the action
|
|
|
|
if (['MUTE', 'BAN'].includes(infType)) {
|
|
|
|
|
|
|
|
response = await message.prompt(message.format('S_FILTER_ACTION_ADD_TIMER', { action: infType }));
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(action.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!['no', 'n'].includes(response.content.toLowerCase())) {
|
|
|
|
const time = resolver.resolveTime(response.content);
|
|
|
|
if (!time) message.formattedRespond('S_FILTER_ACTION_ADD_TIMER_FAIL');
|
|
|
|
else actionObject.duration = time;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const settings = message.guild._settings;
|
2020-09-30 23:02:03 +02:00
|
|
|
//Add points & expiration to action if modpoints are enabled
|
2020-09-27 20:14:01 +02:00
|
|
|
if (settings.moderationPoints?.enabled) {
|
|
|
|
|
2020-09-30 23:02:03 +02:00
|
|
|
// Points
|
2020-09-27 20:14:01 +02:00
|
|
|
response = await message.prompt(message.format('S_FILTER_ACTION_ADD_POINTS'));
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(action.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!['no', 'n'].includes(response.content.toLowerCase())) {
|
|
|
|
|
|
|
|
const points = /(\d{1,3})\s?(points?|pts?|p)?/iu;
|
|
|
|
const match = response.content.match(points);
|
|
|
|
if (!match) message.formattedRespond('S_FILTER_ACTION_ADD_POINTS_FAIL');
|
|
|
|
else {
|
|
|
|
let value = parseInt(match[1]);
|
|
|
|
if (value < 0 || value > 100) {
|
|
|
|
if (value < 0) value = 0;
|
|
|
|
else value = 100;
|
|
|
|
message.formattedRespond('S_FILTER_ACTION_ADD_POINTS_RANGE', { params: { value } });
|
|
|
|
}
|
|
|
|
actionObject.points = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-09-30 23:02:03 +02:00
|
|
|
// Expiration
|
|
|
|
response = await message.prompt(message.format('S_FILTER_ACTION_ADD_EXPIRATION'));
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(action.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!['no', 'n'].includes(response.content.toLowerCase())) {
|
|
|
|
|
|
|
|
const time = resolver.resolveTime(response.content);
|
|
|
|
if (!time) message.formattedRespond('S_FILTER_ACTION_ADD_EXPIRATION_FAIL');
|
|
|
|
else actionObject.expiration = time;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-09-27 20:14:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//Should it force the action if automod is enabled
|
|
|
|
if (settings.autoModeration?.enabled) {
|
|
|
|
|
|
|
|
response = await message.prompt(message.format('S_FILTER_ACTION_ADD_FORCE'));
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(action.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
if (['yes', 'ye', 'y'].includes(response.content.toLowerCase())) {
|
|
|
|
actionObject.force = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//Should the action also prune the user's messages
|
|
|
|
if (infType !== 'SOFTBAN') {
|
|
|
|
response = await message.prompt(message.format('S_FILTER_ACTION_ADD_PRUNE'));
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(action.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
if (['yes', 'ye', 'y'].includes(response.content.toLowerCase())) {
|
|
|
|
actionObject.prune = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-11 23:58:47 +01:00
|
|
|
//What should trigger the action?
|
2020-09-28 00:09:33 +02:00
|
|
|
//Implemented in the subclass
|
|
|
|
const result = await this._createTrigger(message, action, actionObject, setting);
|
|
|
|
if (result && result.error) return result;
|
2020-09-27 20:14:01 +02:00
|
|
|
|
|
|
|
setting.actions.push(actionObject);
|
|
|
|
return actionObject;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
async _createTrigger() {
|
|
|
|
throw new Error(`${this.name} requires an implementation for \`_createTrigger\``);
|
|
|
|
}
|
|
|
|
|
|
|
|
async _removeAction(message, setting) {
|
|
|
|
|
|
|
|
const { actions } = setting;
|
|
|
|
const embed = this._createActionEmbed(message, setting);
|
|
|
|
const response = await message.prompt({ content: message.format('S_FILTER_ACTION_REMOVE_START'), embed }, { time: 60 * 1000 });
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(response.content.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
const index = parseInt(response.content);
|
|
|
|
if (isNaN(index)) return { error: true, msg: message.format('ERR_NAN') };
|
|
|
|
if (index < 0 || index > actions.length - 1) return { error: true, msg: message.format('ERR_INDEX_OUT_OF_BOUNDS') };
|
|
|
|
|
|
|
|
return setting.actions.splice(index, 1)[0];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
async _editAction(message, setting) {
|
|
|
|
|
|
|
|
const { actions } = setting;
|
|
|
|
const embed = this._createActionEmbed(message, setting);
|
|
|
|
let response = await message.prompt({ content: message.format('S_FILTER_ACTION_EDIT_START'), embed }, { time: 60 * 1000 });
|
|
|
|
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(response.content.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
const index = parseInt(response.content);
|
|
|
|
if (isNaN(index)) return { error: true, msg: message.format('ERR_NAN') };
|
|
|
|
if (index < 0 || index > actions.length - 1) return { error: true, msg: message.format('ERR_INDEX_OUT_OF_BOUNDS') };
|
|
|
|
|
|
|
|
const action = actions[index];
|
|
|
|
|
|
|
|
//Which property do you want to edit?
|
|
|
|
const properties = Object.keys(action);
|
|
|
|
response = await message.prompt(message.format('S_FILTER_ACTION_EDIT_SELECT', { properties: properties.join('`, `') }));
|
|
|
|
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(response.content.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
const prop = response.content.toLowerCase();
|
|
|
|
if (!properties.includes(prop)) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('S_FILTER_ACTION_EDIT_BADPROP')
|
|
|
|
};
|
|
|
|
|
|
|
|
if (prop === 'trigger') return this._editTrigger(message, setting, action);
|
|
|
|
else if (prop === 'duration') return this._editDuration(message, setting, action);
|
|
|
|
else if (prop === 'points') return this._editPoints(message, setting, action);
|
2020-09-30 23:02:03 +02:00
|
|
|
else if (prop === 'expiration') return this._editExpiration(message, setting, action);
|
2020-09-27 20:14:01 +02:00
|
|
|
else if (prop === 'action') return this._editType(message, setting, action);
|
|
|
|
else if (['force', 'prune'].includes(prop)) return this._editBool(message, setting, action, prop);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-09-30 23:02:03 +02:00
|
|
|
async _editExpiration(message, setting, action) {
|
|
|
|
|
|
|
|
if (!message.guild._settings.moderationPoints?.enabled) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('S_FILTER_ACTION_EDIT_POINTS_DISABLED')
|
|
|
|
};
|
|
|
|
|
|
|
|
const response = await message.prompt(message.format('S_FILTER_ACTION_EDIT_EXPIRATION', {}), { time: 60 * 1000 });
|
|
|
|
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(response.content.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
const { resolver } = this.client;
|
|
|
|
|
|
|
|
const time = resolver.resolveTime(response.content);
|
|
|
|
if (time === null) message.formattedRespond('S_FILTER_ACTION_ADD_EXPIRATION_FAIL');
|
|
|
|
else action.expiration = time;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-09-27 20:14:01 +02:00
|
|
|
async _editBool(message, setting, action, prop) {
|
|
|
|
|
|
|
|
const response = await message.prompt(message.format('S_FILTER_ACTION_EDIT_BOOL', { prop }), { time: 120 * 1000 });
|
|
|
|
const { resolver } = this.client;
|
|
|
|
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(response.content.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
const bool = resolver.resolveBoolean(response.content);
|
|
|
|
if (bool === null) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('S_FILTER_ACTION_EDIT_BOOL_INVALID')
|
|
|
|
};
|
|
|
|
|
|
|
|
action[prop] = bool;
|
|
|
|
return action;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
async _editPoints(message, setting, action) {
|
|
|
|
|
|
|
|
if (!message.guild._settings.moderationPoints?.enabled) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('S_FILTER_ACTION_EDIT_POINTS_DISABLED')
|
|
|
|
};
|
|
|
|
|
2020-09-30 23:02:03 +02:00
|
|
|
const response = await message.prompt(message.format('S_FILTER_ACTION_EDIT_POINTS', {}), { time: 60 * 1000 });
|
2020-09-27 20:14:01 +02:00
|
|
|
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(response.content.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
const reg = /(\d{1,3})\s?(points?|pts?|p)?/iu;
|
|
|
|
if (!reg.test(response.content)) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('S_FILTER_ACTION_EDIT_POINTS_FAIL')
|
|
|
|
};
|
|
|
|
|
|
|
|
const match = response.content.match(reg);
|
|
|
|
let points = parseInt(match[1]);
|
|
|
|
if (points < 0 || points > 100) {
|
|
|
|
if (points < 0) points = 0;
|
|
|
|
else if (points > 100) points = 100;
|
|
|
|
message.respond('S_FILTER_ACTION_ADD_POINTS_RANGE', { value: points });
|
|
|
|
}
|
|
|
|
|
|
|
|
action.points = points;
|
|
|
|
return action;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
async _editType(message, setting, action) {
|
|
|
|
|
|
|
|
const response = await message.prompt(message.format('S_FILTER_ACTION_EDIT_TYPE', { valid: validInfractions.join('`, `') }), { time: 120 * 1000 });
|
|
|
|
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(response.content.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!validInfractions.includes(response.content.toUpperCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('S_FILTER_ACTION_EDIT_INVALID_TYPE')
|
|
|
|
};
|
|
|
|
|
2020-09-30 23:02:03 +02:00
|
|
|
action.type = response.content.toUpperCase();
|
|
|
|
if (['BAN', 'MUTE'].includes(action.type) && !action.duration) return this._editDuration(message, setting, action);
|
2020-09-27 20:14:01 +02:00
|
|
|
|
|
|
|
action.duration = null;
|
|
|
|
return action;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
async _editDuration(message, setting, action) {
|
|
|
|
|
2020-09-30 23:02:03 +02:00
|
|
|
if (!['MUTE', 'BAN'].includes(action.type)) return {
|
2020-09-27 20:14:01 +02:00
|
|
|
error: true,
|
2020-09-30 23:02:03 +02:00
|
|
|
msg: message.format('S_FILTER_ACTION_EDIT_DURATION_ERR', { action: action.type })
|
2020-09-27 20:14:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const response = await message.prompt(message.format('S_FILTER_ACTION_EDIT_DURATION', {}), { time: 120 * 1000 });
|
|
|
|
const { resolver } = this.client;
|
|
|
|
|
|
|
|
if (!response) return { error: true, msg: message.format('ERR_TIMEOUT') };
|
|
|
|
if (['cancel', 'abort', 'exit'].includes(response.content.toLowerCase())) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('ERR_CANCEL')
|
|
|
|
};
|
|
|
|
|
|
|
|
if (response.content === '0') {
|
|
|
|
action.duration = null;
|
|
|
|
} else {
|
|
|
|
const time = resolver.resolveTime(response.content);
|
|
|
|
if (!time) return {
|
|
|
|
error: true,
|
|
|
|
msg: message.format('S_FILTER_ACTION_EDIT_DURATION_ERR2')
|
|
|
|
};
|
|
|
|
action.duration = time;
|
|
|
|
}
|
|
|
|
|
|
|
|
return action;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
async _listActions(message, setting) {
|
|
|
|
|
|
|
|
if (!setting.actions.length) return message.formattedRespond('S_FILTER_NOACTIONS');
|
|
|
|
return message.respond(message.format('S_FILTER_CURRENT_ACTIONS'), { embed: this._createActionEmbed(message, setting) });
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//Create embed to display current actions
|
|
|
|
_createActionEmbed(message, setting) {
|
|
|
|
|
|
|
|
const { resolver } = this.client;
|
|
|
|
const { actions } = setting;
|
|
|
|
const embed = {
|
|
|
|
fields: actions.map((action) => {
|
|
|
|
return {
|
2020-09-30 23:02:03 +02:00
|
|
|
name: `**[${actions.indexOf(action)}]** ${action.type}`,
|
2020-09-27 20:14:01 +02:00
|
|
|
value: message.format('S_FILTER_ACTION_PROPERTIES', {
|
|
|
|
duration: action.duration ? resolver.timeAgo(action.duration) : 'INF',
|
|
|
|
points: action.points || message.format('ON_OFF_TOGGLE', { toggle: false }, true),
|
|
|
|
prune: message.format('ON_OFF_TOGGLE', { toggle: action.prune }, true),
|
|
|
|
force: message.format('ON_OFF_TOGGLE', { toggle: action.force }, true),
|
|
|
|
trigger: action.trigger instanceof Array ? action.trigger.join(', ') : '`' + action.trigger + '`'
|
|
|
|
}),
|
|
|
|
inline: true
|
|
|
|
};
|
|
|
|
}),
|
|
|
|
color: 619452
|
|
|
|
};
|
|
|
|
if (embed.fields.length % 3 === 2) embed.fields.push({
|
|
|
|
name: '\u200b',
|
|
|
|
value: '\u200b',
|
|
|
|
inline: true
|
|
|
|
});
|
|
|
|
return embed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|