This commit is contained in:
nolan 2020-05-23 23:50:42 -04:00
commit b041be78bd
13 changed files with 399 additions and 67 deletions

View File

@ -37,6 +37,7 @@ __**Warning:** This is a long embed.__
__**{component} HELP**__
{desc}
**Example usage**
{text}

View File

@ -24,4 +24,17 @@ Arguments
Current Settings
[GENERAL_SETTINGRESET]
Successfully reset the setting {setting} to the default value.
Successfully reset the setting **{setting}** to the default value.
[GENERAL_ADDED]
added
[GENERAL_REMOVED]
removed
[ERR_INVALID_METHOD]
Method `{method}` is invalid!
[PREMIUM_2]
Sorry! This is a tier 2 premium feature.
Current server tier: `{tier}`

View File

@ -1,6 +1,6 @@
//modlogs setting
[S_MODLOGS_DESCRIPTION]
[S_MODERATIONLOG_DESCRIPTION]
Define the channel to which moderation logs are sent. The setting also allows you to exclude types of actions from being logged in the channel.
[S_MODLOGS_CHANNEL404]
@ -9,9 +9,58 @@ Define the channel to which moderation logs are sent. The setting also allows yo
[S_MODLOGS_CHANNEL_SUCCESS]
Successfully set the modlogs channel to {channel}.
[S_MODLOGS_EXCLUDE404]
[S_MODLOGS_ARGS404]
Missing arguments.
[S_MODLOGS_LIST]
The following infractions are set to be logged:
`{list}`
[S_MODLOGS_REMOVE]
The followin infraction types will no longer be logged:
`{list}`
[S_MODLOGS_ADD]
The followin infraction types will now be logged:
`{list}`
//CHATLOGS SETTING
[S_CHATLOGS_DESCRIPTION]
Configure message logging for your server.
[S_CHATLOGS_ROLES_LIST]
The following roles are ignored by chatlogs:
{roles}
[S_CHATLOGS_CHANNELS_LIST]
The following channels are ignored by chatlogs:
{channels}
[S_CHATLOGS_ROLES]
Successfully {action} the following roles:
{changed}
[S_CHATLOGS_CHANNELS]
Successfully {action} the following channels:
{changed}
[S_CHATLOGS_ATTACHMENTS]
Successfully turned attachment logging {changed}
[S_CHATLOGS_TOGGLE]
switch({toggle}) {
case true:
'on';
break;
case false:
'off';
break;
}
[S_CHATLOGS_RESET]
Successfully reset the chatlogs setting.
//mute Setting
[S_MUTE_DESCRIPTION]

View File

@ -39,6 +39,62 @@ class Resolver {
// resolveFalse(input) {
// return [].includes(input.toLowerCase());
// }
/**
* Resolves methods used primarily for settings, also deals with appending the arguments into existing lists
*
* @param {Array<String>} args The incoming arguments with the first element being the method ex. ['add','ban','kick']
* @param {Array<String>} valid An array of items to compare to, if an argument doesn't exist in this array it'll be skipped over
* @param {Array<String>} [existing=[]] Existing values in the array, valid elements will be appended to this
* @returns {Object}
* @memberof Resolver
*/
resolveMethod(args, valid, existing = []) {
const methods = {
list: ['view', 'list', '?'],
add: ['add', '+'],
remove: ['remove', 'delete', '-']
};
if (!args.length) return false;
// eslint-disable-next-line prefer-const
let [method, ...rest] = args;
method = method.toLowerCase();
if (!rest.length) {
if (methods.list.includes(method)) return { method: 'list', rest };
if (methods.add.includes(method)) return { method: 'add', rest };
if (methods.remove.includes(method)) return { method: 'remove', rest };
}
if (methods.list.includes(method)) {
return { method: 'list' };
} else if (methods.add.includes(method)) {
const added = [];
for (let elem of rest) {
elem = elem.toLowerCase();
if (existing.includes(elem) || valid && !valid.includes(elem)) continue;
added.push(elem);
existing.push(elem);
}
return { rest, method: 'add', changed: added, result: existing };
} else if (methods.remove.includes(method)) {
const removed = [];
for (let elem of rest) {
elem = elem.toLowerCase();
if (!existing.includes(elem) || removed.includes(elem) || valid && !valid.includes(elem)) continue;
removed.push(elem);
existing.splice(existing.indexOf(elem), 1);
}
return { rest, method: 'remove', changed: removed, result: existing };
}
return false;
}
async resolveMemberAndUser(string, guild) {

View File

@ -31,14 +31,14 @@ class HelpCommand extends Command {
description: message.format('C_HELP_TEMPLATE', {
desc: message.format(result.description),
component: result.name.toUpperCase(),
text: result.examples.map(ex => `\`{prefix}${result.name} ${ex}\``).join('\n')
})//,
// fields: [
// {
// name: '',
// value: message.format(result.examples)
// }
// ]
text: result.examples.map(ex => `\`{prefix}${result.type === 'command' ? result.name.toLowerCase() : `settings ${result.name.toLowerCase()}`} ${ex}\``).join('\n')
}),
fields: [
{
name: 'Aliases',
value: result.aliases.map(al => al.toLowerCase()).join(', ')
}
]
});
}

View File

@ -73,7 +73,7 @@ class SettingsCommand extends Command {
}
}
setting._caller = target;
message._settingCaller = target;
if(setting.resolve === 'GUILD' && !this._checkAdministrator(message)) return undefined; //does not have admin
const parameters = params.splice(1);
@ -83,7 +83,8 @@ class SettingsCommand extends Command {
}
if(parameters.join(' ').toLowerCase() === 'reset') {
return await setting._handleReset(message);
const { msg } = await setting._handleReset(message);
return message.respond(msg, { emoji: 'success' });
}
const response = await setting.handle(message, parameters);

View File

@ -161,6 +161,8 @@ class CommandHandler extends Observer {
const { shortFlags, longFlags, keys } = await this._createFlags(passedArguments);
const regex = new RegExp(`([0-9]*)(${Object.keys(longFlags).map(k=>escapeRegex(k)).join('|')})([0-9]*)`, 'i');
//console.log('args')
//console.log(args)
let parsedArguments = [];
let params = [];
@ -217,6 +219,7 @@ class CommandHandler extends Observer {
continue;
} else {
let match = regex.exec(word);
//console.log(match)
if(match && match[2]) {
currentArgument = longFlags[match[2]];
if(params.length > 0 && ['INTEGER', 'FLOAT'].includes(currentArgument.type)) { //15 pts
@ -258,8 +261,10 @@ class CommandHandler extends Observer {
continue;
}
} else {
//console.log(currentArgument?.name)
if(currentArgument) {
const error = await this._handleTypeParsing(currentArgument, word, guild);
//console.log(error)
if(error) {
if(currentArgument.default !== null) {
params.push(word);

View File

@ -0,0 +1,197 @@
const { Setting } = require('../../../../interfaces/');
class Chatlogs extends Setting {
constructor(client) {
super(client, {
name: 'messageLogs',
module: 'moderation',
index: 'chatlogs',
aliases: [
'chatLog',
'chatLogs',
'msgLogs'
],
guarded: true,
resolve: 'GUILD',
examples: [
'chatlogs roles <add|remove|list> <role>',
'chatlogs channels <add|remove|list> <role>',
'chatlogs reset',
'chatlogs attachments <on|off>',
'chatlogs #channel'
],
default: {
chatlogs: {
channel: undefined,
ignoredChannels: [],
ignoredRoles: [],
attachments: false
}
}
});
this.client = client;
}
async handle(message, params) {
// eslint-disable-next-line init-declarations
let index, changes, action;
// eslint-disable-next-line prefer-const
let [method, ...args] = params;
method = method.toLowerCase();
const setting = message.guild._settings.chatlogs || this.default.chatlogs;
const { guild } = message;
if (method === 'roles') {
const response = this.resolveMethod(args);
if (response) {
if (response.method === 'add') {
const roles = await guild.resolveRoles(response.rest);
setting.ignoredRoles = [...setting.ignoredRoles, ...roles.filter(r => !setting.ignoredRoles.includes(r.id)).map(r => r.id)];
action = 'GENERAL_ADDED';
index = 'S_CHATLOGS_ROLES';
changes = roles.map(r => r.name);
} else if (response.method === 'remove') {
const roles = await guild.resolveRoles(response.rest);
const _roles = roles.map(r => r.id);
setting.ignoredRoles = setting.ignoredRoles.filter(r => !_roles.includes(r));
action = 'GENERAL_REMOVED';
index = 'S_CHATLOGS_ROLES';
changes = roles.map(r => r.name);
} else if (response.method === 'list') {
const roles = await guild.resolveRoles(setting.ignoredRoles);
return {
msg: message.format('S_CHATLOGS_ROLES_LIST', { roles: roles.map(r => r.name).join(', ') })
};
}
} else {
return {
msg: message.format('ERR_INVALID_METHOD', { method })
};
}
} else if (method === 'channels') {
const response = this.resolveMethod(args);
if (response) {
if (response.method === 'add') {
const channels = guild.resolveChannels(response.rest);
setting.ignoredChannels = [...setting.ignoredChannels, ...channels.filter(c => !setting.ignoredChannels.includes(c.id)).map(c => c.id)];
action = 'GENERAL_ADDED';
index = 'S_CHATLOGS_CHANNELS';
changes = channels.map(c => c.name);
} else if (response.method === 'remove') {
const channels = guild.resolveChannels(response.rest);
const _channels = channels.map(c => c.id);
setting.ignoredChannels = setting.ignoredChannels.filter(c => !_channels.includes(c));
action = 'GENERAL_REMOVED';
index = 'S_CHATLOGS_CHANNELS';
changes = channels.map(c => c.name);
} else if (response.method === 'list') {
return {
msg: message.format('S_CHATLOGS_LIST')
};
}
changes = response.changed;
} else {
const channels = guild.resolveChannels(setting.ignoredChannels);
return {
msg: message.format('S_CHATLOGS_ROLES_LIST', { roles: channels.map(r => r.name).join(', ') })
};
}
} else if (method === 'attachments') {
if (guild.premium < 2) return {
msg: message.format('PREMIUM_2', { tier: guild.premium }),
error: true
}
const [bool] = args;
const result = this.client.resolver.resolveBoolean(bool);
if (result) {
setting.attachments = true;
index = 'S_CHATLOGS_ATTACHMENTS';
changes = message.format('S_CHATLOGS_TOGGLE', { toggle: true }, true);
} else {
setting.attachments = false;
index = 'S_CHATLOGS_ATTACHMENTS';
changes = message.format('S_CHATLOGS_TOGGLE', { toggle: false }, true);
}
} else {
const channel = message.guild.resolveChannel(args[0]);
if (!channel) return {
msg: message.format('S_CHATLOGS_CHANNEL404'),
error: true
};
setting.channel = channel.id;
}
await message.guild._updateSettings({ [this.index]: setting });
return {
msg: message.format(index, { changed: changes instanceof Array ? changes?.join(', ') : changes || undefined, action: message.format(action) })
};
}
async fields(guild) {
const roles = guild._settings[this.index]?.ignoredRoles ? await Promise.all(guild._settings[this.index].ignoredRoles.map(async (role) => guild.resolveRole(role))) : undefined;
return [
{
name: 'Channel',
value: guild.resolveChannel(guild._settings[this.index]?.channel) || 'N/A',
inline: true
},
{
name: 'Ignored roles',
value: roles?.map((r) => r.name).join(', ') || 'N/A',
inline: true
},
{
name: 'Ignored channels',
value: guild._settings[this.index]?.ignoredChannels.map((c) => guild.resolveChannel(c).name).join(', ') || 'N/A',
inline: true
}
];
}
}
module.exports = Chatlogs;

View File

@ -1,5 +1,9 @@
const { Setting } = require('../../../../interfaces/');
const CONSTANTS = {
INFRACTIONS: ['note', 'warn', 'mute', 'unmute', 'lockdown', 'lockdownend', 'kick', 'ban', 'unban', 'vcmute', 'vcunmute', 'vckick', 'vcban', 'vcunban', 'prune', 'slowmode', 'dehoist', 'addrole', 'removerole', 'nickname']
};
class Modlogs extends Setting {
constructor(client) {
@ -14,24 +18,16 @@ class Modlogs extends Setting {
],
guarded: true,
resolve: 'GUILD',
//custom: true,
index: 'modlogs',
examples: [
'modlog #moderation-log',
'modlog reset'
],
arguments: [
{
name: 'exclude',
type: 'STRING',
types: ['VERBAL'],
requiredValue: true,
infinite: true
}
'modlogs <add|remove|list> <infraction-type..>',
'modlogs #moderation-log',
'modlogs reset'
],
default: {
modlogs: {
channel: undefined,
exclude: []
infractions: ['warn','mute','unmute','lockdown','lockdownend','kick','ban','unban','vcmute','vcunmute','vckick','vcban','vcunban']
}
}
});
@ -42,52 +38,52 @@ class Modlogs extends Setting {
async handle(message, args) {
const { params, parsedArguments } = await this._parseArguments(args, message.guild, true);
let setting = message.guild._settings.modlogs || { };
const setting = message.guild._settings.modlogs || this.default.modlogs;
const response = this.resolveMethod(args, CONSTANTS.INFRACTIONS, setting.infractions);
if (parsedArguments.exclude) {
if (!parsedArguments.exclude.value.length) return {
msg: message.format('S_MODLOGS_EXCLUDE404'),
if (response) {
if (args.length < 2 && response.method !== 'list') return {
msg: message.format('S_MODLOGS_ARGS404'),
error: true
}
let index;
if (response.method === 'add') {
setting.infractions = response.result;
index = 'S_MODLOGS_ADD';
} else if (response.method === 'remove') {
setting.infractions = response.result;
index = 'S_MODLOGS_REMOVE';
} else if (response.method === 'list') {
return {
msg: message.format('S_MODLOGS_LIST', { list: setting.infractions.join('`, `') })
}
}
if(response.changed.length) await message.guild._updateSettings({ [this.index]: setting });
return { msg: message.format(index, { list: response.changed.length ? response.changed.join('`, `') : 'N/A' }) };
} else {
let [channel] = params;
if (channel === 'reset') {
channel = message.guild.resolveChannel(channel);
if (!channel) return {
msg: message.format('S_MODLOGS_CHANNEL404', { val: params[0] }),
error: true
};
setting = {};
await message.guild._updateSettings({ [this.index]: setting });
return {
msg: message.format('S_MODLOGS_RESET'),
error: false
};
setting.channel = channel.id;
await message.guild._updateSettings({ [this.index]: setting }); return {
msg: message.format('S_MODLOGS_CHANNEL_SUCCESS', { channel: channel.name }),
error: false
};
} else {
channel = message.guild.resolveChannel(channel);
if (!channel) return {
msg: message.format('S_MODLOGS_CHANNEL404', { val: params[0] }),
error: true
};
setting.channel = channel.id;
await message.guild._updateSettings({ [this.index]: setting }); return {
msg: message.format('S_MODLOGS_CHANNEL_SUCCESS', { channel: channel.name }),
error: false
};
}
}
}
data(guild) {
return `**Prefix:** \`${guild.prefix}\``;
}
fields(guild) {
return [
{
@ -96,8 +92,8 @@ class Modlogs extends Setting {
inline: true
},
{
name: 'Excluded types',
value: guild._settings[this.index]?.exclude.join(', ') || 'N/A',
name: 'Enabled infractions',
value: guild._settings[this.index]?.infractions.join(', ') || 'N/A',
inline: true
}
];

View File

@ -54,7 +54,7 @@ class MuteSetting extends Setting {
const { params, parsedArguments } = await this._parseArguments(args, message.guild);
args = params;
if(['mutetype', 'mutedtype'].includes(this._caller) || parsedArguments.type) {
if(['mutetype', 'mutedtype'].includes(message._settingCaller) || parsedArguments.type) {
const num = args[0].toLowerCase() === 'type' ? args[1] || 0 : args[0];
const number = parseInt(num);
if(isNaN(number)) return {
@ -83,7 +83,7 @@ class MuteSetting extends Setting {
let role = null;
let updatedPermissions = false;
let created = false;
if(parsedArguments.create || this._caller === 'createmute') {
if(parsedArguments.create || message._settingCaller === 'createmute') {
const missing = message.channel.permissionsFor(message.guild.me).missing('MANAGE_ROLES');
if(missing.length > 0) return {
msg: message.format('S_MUTE_ROLEMISSINGPERMISSION'),

View File

@ -26,7 +26,7 @@ class GuildPrefixSetting extends Setting {
async handle(message, params) {
const [ prefix ] = params;
let [ prefix ] = params;
const MaxCharacters = 6;
if(prefix.length > MaxCharacters) return {
@ -39,7 +39,7 @@ class GuildPrefixSetting extends Setting {
error: true
};
if (prefix === 'reset') prefix = this.default.prefix;
if (prefix === 'reset') ({ prefix } = this.default);
await message.guild._updateSettings({ [this.index]: prefix });
return {

View File

@ -11,6 +11,7 @@ const Guild = Structures.extend('Guild', (Guild) => {
this._settings = null; //internal cache of current guild's settings; should ALWAYS stay the same as database.
this._permissions = null; //internal cache, should always match database.
this.premium = 0;
}
@ -78,7 +79,7 @@ const Guild = Structures.extend('Guild', (Guild) => {
async _removeSettings(value) { //Remove property
if(this.client.defaultConfig[value]) {
await this._updateSettings(this.client.defaultConfig[value]);
await this._updateSettings({ [value]: this.client.defaultConfig[value] });
return undefined;
}
try {

View File

@ -47,13 +47,26 @@ class Setting extends Component {
return { parsedArguments: response.parsedArguments, params: response.newArgs, error: false };
}
/**
* Resolves methods used primarily for settings, also deals with appending the arguments into existing lists
*
* @param {Array<String>} args The incoming arguments with the first element being the method ex. ['add','ban','kick']
* @param {Array<String>} valid An array of items to compare to, if an argument doesn't exist in this array it'll be skipped over
* @param {Array<String>} [existing=[]] Existing values in the array, valid elements will be appended to this
* @returns {Object}
* @memberof Resolver
*/
resolveMethod(args, valid, existing) {
return this.client.resolver.resolveMethod(args, valid, existing);
}
reason(executor) {
return `[${this.moduleResolveable}] Executed by ${executor.tag} (${executor.id}).`;
}
async _handleReset(message) {
await message.guild._removeSettings(this.index);
const msg = message.format('GENERAL_SETTINGRESET', { setting: this.resolveable });
const msg = message.format('GENERAL_SETTINGRESET', { setting: this.name.toLowerCase() });
return {
error: false,
msg