This commit is contained in:
Erik 2020-05-24 12:57:21 +03:00
commit e41f2b2bb5
15 changed files with 175 additions and 130 deletions

View File

@ -57,7 +57,7 @@ class LocaleLoader {
let text = '';
for(const line of lines) {
if(line.startsWith('//')) continue;
const matches = line.match(/\[([_A-Z0-9]{1,})\]/iu);
const matches = line.match(/\[([_A-Z0-9]{1,})\]/u);
if(matches) {
if (matched) {
parsed[matched] = text;

View File

@ -3,3 +3,6 @@ View or edit user-only settings.
[A_ALL_SETTINGS_DESCRIPTION]
View all guild, user, or restricted settings.
[A_RAW_SETTINGS_DESCRIPTION]
Upload a raw JSON file of all of the settings for your user or guild.

View File

@ -47,6 +47,10 @@ Alternatively, you can view user settings by using the command `{prefix}settings
[C_SETTINGS_NONEXISTANT]
That setting does not exist!
[C_SETTINGS_JSON]
Attached the JSON-formatted settings file in the file below.
You may want to format this file for your viewing pleasure.
//User Command
[C_USER_DESCRIPTION]

View File

@ -7,7 +7,7 @@ switch({component}) {
"setting";
break;
case "inhibitor":
"inhibitor":
"inhibitor";
break;
}

View File

@ -3,52 +3,52 @@
[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]
[S_MODERATIONLOG_CHANNEL404]
{val} does not resolve into a channel.
[S_MODLOGS_CHANNEL_SUCCESS]
[S_MODERATIONLOG_CHANNEL_SUCCESS]
Successfully set the modlogs channel to {channel}.
[S_MODLOGS_ARGS404]
[S_MODERATIONLOG_ARGS404]
Missing arguments.
[S_MODLOGS_LIST]
[S_MODERATIONLOG_LIST]
The following infractions are set to be logged:
`{list}`
[S_MODLOGS_REMOVE]
[S_MODERATIONLOG_REMOVE]
The followin infraction types will no longer be logged:
`{list}`
[S_MODLOGS_ADD]
[S_MODERATIONLOG_ADD]
The followin infraction types will now be logged:
`{list}`
//CHATLOGS SETTING
[S_MESSAGELOGS_DESCRIPTION]
[S_MESSAGELOG_DESCRIPTION]
Configure message logging for your server.
[S_CHATLOGS_ROLES_LIST]
[S_MESSAGELOG_ROLES_LIST]
The following roles are ignored by chatlogs:
{roles}
[S_CHATLOGS_CHANNELS_LIST]
[S_MESSAGELOG_CHANNELS_LIST]
The following channels are ignored by chatlogs:
{channels}
[S_CHATLOGS_ROLES]
[S_MESSAGELOG_ROLES]
Successfully {action} the following roles:
{changed}
[S_CHATLOGS_CHANNELS]
[S_MESSAGELOG_CHANNELS]
Successfully {action} the following channels:
{changed}
[S_CHATLOGS_ATTACHMENTS]
[S_MESSAGELOG_ATTACHMENTS]
Successfully turned attachment logging {changed}
[S_CHATLOGS_TOGGLE]
[S_MESSAGELOG_TOGGLE]
switch({toggle}) {
case true:
'on';
@ -58,13 +58,13 @@ switch({toggle}) {
break;
}
[S_CHATLOGS_RESET]
[S_MESSAGELOG_RESET]
Successfully reset the chatlogs setting.
//mute Setting
[S_MUTE_DESCRIPTION]
Assign or create a muted role and choose mute functionality for your guild.
Assign or create a muted role and choose mute functionality for your guild. Creating permissions for a role could take longer depending on the amount of channels.
__Mute Types__
**`0`:** Mutes only add/remove the muted role. *(default)*
@ -121,16 +121,3 @@ Successfully {type} the **mute role** to `{role}`.
[S_MUTE_UNGENERATEDPERMISSIONS]
**None of the permissions have been changed.**
[S_MUTEDROLE_MISSINGPERMISSION]
The bot must have the `MANAGE_ROLES` permission to create a new muted role in the guild.
[S_MUTEDROLE_ERRORCREATE]
There was an issue creating the muted role for your guild.
[S_MUTEDROLE_CANNOTFIND]
I cannot find a role name with those arguments. If you would like to create a new one, use the command `{prefix}settings mute create`.
[S_MUTEDROLE_SUCCESS]
Successfully set the muted role to `{role}`.

View File

@ -18,7 +18,35 @@ The guild prefix cannot include spaces.
[S_GUILDPREFIX_RESET]
Successfully reset the guild prefix to `{prefix}`.
//permissionType Setting
[S_PERMISSIONTYPE_DESCRIPTION]
Changes how permissions will be regarded for bot commands.
__Permission Types__
**`discord`:** Only discord-based permissions work with bot commands.
**`grant`:** Only grantable permissions from the bot work with bot commands. *(requires you to set everything up yourself)*
**`both`:** Both discord-based and grantable permissions work with bot commands. *(default)*
[S_PERMISSIONTYPE_INVALIDTYPE]
The provided value is not a valid permission type; try: `discord`, `grant`, or `both`.
Use the command `{prefix}setting permissiontype` for more information.
[S_PERMISSIONTYPE_SUCCESS]
Successfully set permission type to `{type}`.
**{description}**
[S_PERMISSIONTYPE_DESCRIPTIONS]
switch('{type}') {
case 'discord':
"Only discord-based permissions will work with bot commands."
break;
case 'grant':
"Only grantable permissions from the bot will work with bot commands."
break;
case 'both':
"Both discord-based and grantable permissions work with bot commands."
break;
}
//User Settings

View File

@ -32,14 +32,6 @@ class Resolver {
}
// resolveTrue(input) {
// return [ 'on', 'true' ].includes(input.toLowerCase());
// }
// resolveFalse(input) {
// return [].includes(input.toLowerCase());
// }
/**
* Resolves methods used primarily for settings, also deals with appending the arguments into existing lists
*

View File

@ -1,3 +1,4 @@
const { MessageAttachment } = require('discord.js');
const { Command } = require('../../../../interfaces');
const { stripIndents } = require('common-tags');
@ -26,13 +27,24 @@ class SettingsCommand extends Command {
type: 'BOOLEAN',
types: ['VERBAL', 'FLAG'],
default: true
},
{
name: 'raw',
aliases: ['json'],
type: 'BOOLEAN',
types: ['VERBAL', 'FLAG'],
default: true
}
],
showUsage: true,
examples: [
'prefix !',
'modlogs #channel'
]
],
throttling: {
usages: 1,
duration: 3
}
});
this.client = client;
@ -44,6 +56,8 @@ class SettingsCommand extends Command {
const type = (!message.guild || args.user) ? 'USER' : 'GUILD';
if(args.raw) return this._showRaw(message, type);
const target = params[0].toLowerCase(); // params[0] should never be null, see showUsage
if(target === 'list') {
this._listSettings(message, type, Boolean(args.all));
@ -52,9 +66,6 @@ class SettingsCommand extends Command {
if(type === 'GUILD' && !this._checkAdministrator(message)) return undefined; //does not have admin
const prompt = await message.prompt(message.format('C_SETTINGS_RESET', { type: type.toLowerCase() }), { emoji: 'warning' });
return await this._handleReset(prompt, message, type);
} else if(target === 'walkthrough') {
//TODO
return undefined;
}
const settings = this.client.resolver.components(target, 'setting', false).sort(c=>c.resolve === type);
@ -95,7 +106,7 @@ class SettingsCommand extends Command {
_listSettings(message, type, all) {
if(!message.guild && type === 'GUILD') type = 'USER';
const prefix = message.guild?.prefix || this.client._options.bot.prefix; //eslint-disable-line parsing-error
const prefix = message.guild?.prefix;
let fields = [];
const sorted = this.client.registry.components
@ -143,7 +154,7 @@ class SettingsCommand extends Command {
${message.format(setting.description)}`;
if(setting.examples.length > 0) {
description += `\n\n**${message.format('GENERAL_EXAMPLES')}**`;
description += `\n\n__${message.format('GENERAL_EXAMPLES')}__`;
for(let example of setting.examples) {
description += `\n\`${prefix}settings ${example}\``;
}
@ -181,6 +192,19 @@ class SettingsCommand extends Command {
}
async _showRaw(message, type) {
const settings = type === 'USER'
? message.author._settings
: message.guild._settings;
const string = JSON.stringify(settings);
const attachment = new MessageAttachment(Buffer.from(string), "settings.json");
return await message.respond(message.format('C_SETTINGS_JSON'), { emoji: 'success', attachments: [ attachment ] })
}
_checkAdministrator(message) {
const missing = message.channel.permissionsFor(message.member).missing(['ADMINISTRATOR']);
if(missing > 0) {

View File

@ -51,7 +51,7 @@ class CommandHandler extends Observer {
async _getCommand(message, [arg1, arg2, ...args]) {
if(message.guild) await message.guild.settings();
const prefix = message.guild?.prefix || this.client._options.bot.prefix;
const prefix = message.guild?.prefix;
let command = null;
let remains = [];

View File

@ -1,30 +1,32 @@
const { Setting } = require('../../../../interfaces/');
class Chatlogs extends Setting {
class MessageLogsSetting extends Setting {
constructor(client) {
super(client, {
name: 'messageLogs',
name: 'messageLog',
module: 'moderation',
index: 'chatlogs',
aliases: [
'chatLog',
'chatLogs',
'msgLogs'
'msgLogs',
'messageLogs',
'msgLog'
],
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'
'msglog roles <add|remove|list> <role>',
'msglog channels <add|remove|list> <role>',
'msglog reset',
'msglog attachments <on|off>',
'msglog #channel'
],
default: {
chatlogs: {
channel: undefined,
messageLog: {
channel: null,
ignoredChannels: [],
ignoredRoles: [],
attachments: false
@ -44,10 +46,10 @@ class Chatlogs extends Setting {
let [method, ...args] = params;
method = method.toLowerCase();
const setting = message.guild._settings.chatlogs || this.default.chatlogs;
const setting = message.guild._settings[this.index];
const { guild } = message;
if (method === 'roles') {
if (['roles', 'role', 'ignoredrole', 'ignoredroles'].includes(method)) {
const response = this.resolveMethod(args);
@ -59,7 +61,7 @@ class Chatlogs extends Setting {
setting.ignoredRoles = [...setting.ignoredRoles, ...roles.filter(r => !setting.ignoredRoles.includes(r.id)).map(r => r.id)];
action = 'GENERAL_ADDED';
index = 'S_CHATLOGS_ROLES';
index = 'S_MESSAGELOG_ROLES';
changes = roles.map(r => r.name);
} else if (response.method === 'remove') {
@ -69,14 +71,14 @@ class Chatlogs extends Setting {
setting.ignoredRoles = setting.ignoredRoles.filter(r => !_roles.includes(r));
action = 'GENERAL_REMOVED';
index = 'S_CHATLOGS_ROLES';
index = 'S_MESSAGELOG_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(', ') })
msg: message.format('S_MESSAGELOG_ROLES_LIST', { roles: roles.map(r => r.name).join(', ') })
};
}
@ -87,7 +89,7 @@ class Chatlogs extends Setting {
};
}
} else if (method === 'channels') {
} else if (['channels', 'channel', 'ignoredchannels', 'ignoredchannel'].includes(method)) {
const response = this.resolveMethod(args);
@ -99,7 +101,7 @@ class Chatlogs extends Setting {
setting.ignoredChannels = [...setting.ignoredChannels, ...channels.filter(c => !setting.ignoredChannels.includes(c.id)).map(c => c.id)];
action = 'GENERAL_ADDED';
index = 'S_CHATLOGS_CHANNELS';
index = 'S_MESSAGELOG_CHANNELS';
changes = channels.map(c => c.name);
} else if (response.method === 'remove') {
@ -109,12 +111,12 @@ class Chatlogs extends Setting {
setting.ignoredChannels = setting.ignoredChannels.filter(c => !_channels.includes(c));
action = 'GENERAL_REMOVED';
index = 'S_CHATLOGS_CHANNELS';
index = 'S_MESSAGELOG_CHANNELS';
changes = channels.map(c => c.name);
} else if (response.method === 'list') {
return {
msg: message.format('S_CHATLOGS_LIST')
msg: message.format('S_MESSAGELOG_LIST')
};
}
@ -123,12 +125,12 @@ class Chatlogs extends Setting {
} else {
const channels = guild.resolveChannels(setting.ignoredChannels);
return {
msg: message.format('S_CHATLOGS_ROLES_LIST', { roles: channels.map(r => r.name).join(', ') })
msg: message.format('S_MESSAGELOG_ROLES_LIST', { roles: channels.map(r => r.name).join(', ') })
};
}
} else if (method === 'attachments') {
} else if (['attachments', 'images', 'attachment', 'image'].includes(method)) {
if (guild.premium < 2) return {
msg: message.format('PREMIUM_2', { tier: guild.premium }),
@ -141,14 +143,14 @@ class Chatlogs extends Setting {
if (result) {
setting.attachments = true;
index = 'S_CHATLOGS_ATTACHMENTS';
changes = message.format('S_CHATLOGS_TOGGLE', { toggle: true }, true);
index = 'S_MESSAGELOG_ATTACHMENTS';
changes = message.format('S_MESSAGELOG_TOGGLE', { toggle: true }, true);
} else {
setting.attachments = false;
index = 'S_CHATLOGS_ATTACHMENTS';
changes = message.format('S_CHATLOGS_TOGGLE', { toggle: false }, true);
index = 'S_MESSAGELOG_ATTACHMENTS';
changes = message.format('S_MESSAGELOG_TOGGLE', { toggle: false }, true);
}
@ -156,7 +158,7 @@ class Chatlogs extends Setting {
const channel = message.guild.resolveChannel(args[0]);
if (!channel) return {
msg: message.format('S_CHATLOGS_CHANNEL404'),
msg: message.format('S_MESSAGELOG_CHANNEL404'),
error: true
};
@ -175,18 +177,18 @@ class Chatlogs extends Setting {
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',
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',
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',
name: '》Ignored Channels',
value: guild._settings[this.index]?.ignoredChannels.map((c) => guild.resolveChannel(c).name).join(', ') || '`N/A`',
inline: true
}
];
@ -194,4 +196,4 @@ class Chatlogs extends Setting {
}
module.exports = Chatlogs;
module.exports = MessageLogsSetting;

View File

@ -1,10 +1,10 @@
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']
INFRACTIONS: ['note', 'warn', 'mute', 'unmute', 'lockdown', 'unlockdown', 'kick', 'ban', 'unban', 'vcmute', 'vcunmute', 'vckick', 'vcban', 'vcunban', 'prune', 'slowmode', 'dehoist', 'addrole', 'removerole', 'nickname']
};
class Modlogs extends Setting {
class ModerationLogsSetting extends Setting {
constructor(client) {
@ -19,14 +19,14 @@ class Modlogs extends Setting {
guarded: true,
resolve: 'GUILD',
examples: [
'modlogs <add|remove|list> <infraction-type..>',
'modlogs #moderation-log',
'modlogs reset'
'modlog <add|remove|list> <infraction-type..>',
'modlog #moderation-log',
'modlog reset'
],
default: {
modlogs: {
channel: undefined,
infractions: ['warn','mute','unmute','lockdown','lockdownend','kick','ban','unban','vcmute','vcunmute','vckick','vcban','vcunban']
moderationLog: {
channel: null,
infractions: ['warn','mute','unmute','lockdown','unlockdown','kick','ban','unban','vcmute','vcunmute','vckick','vcban','vcunban']
}
}
});
@ -43,20 +43,20 @@ class Modlogs extends Setting {
if (response) {
if (args.length < 2 && response.method !== 'list') return {
msg: message.format('S_MODLOGS_ARGS404'),
msg: message.format('S_MODERATIONLOG_ARGS404'),
error: true
}
let index;
if (response.method === 'add') {
setting.infractions = response.result;
index = 'S_MODLOGS_ADD';
index = 'S_MODERATIONLOG_ADD';
} else if (response.method === 'remove') {
setting.infractions = response.result;
index = 'S_MODLOGS_REMOVE';
index = 'S_MODERATIONLOG_REMOVE';
} else if (response.method === 'list') {
return {
msg: message.format('S_MODLOGS_LIST', { list: setting.infractions.join('`, `') })
msg: message.format('S_MODERATIONLOG_LIST', { list: setting.infractions.join('`, `') })
}
}
@ -69,13 +69,13 @@ class Modlogs extends Setting {
channel = message.guild.resolveChannel(channel);
if (!channel) return {
msg: message.format('S_MODLOGS_CHANNEL404', { val: params[0] }),
msg: message.format('S_MODERATIONLOG_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 }),
msg: message.format('S_MODERATIONLOG_CHANNEL_SUCCESS', { channel: channel.name }),
error: false
};
@ -86,13 +86,13 @@ class Modlogs extends Setting {
fields(guild) {
return [
{
name: 'Channel',
value: guild.resolveChannel(guild._settings[this.index]?.channel) || 'N/A',
name: 'Channel',
value: guild.resolveChannel(guild._settings[this.index]?.channel) || '`N/A`',
inline: true
},
{
name: 'Enabled infractions',
value: guild._settings[this.index]?.infractions.join(', ') || 'N/A',
name: '》Logged Infractions',
value: guild._settings[this.index].infractions.map(i=>`\`${i}\``).join(', ') || '`N/A`',
inline: true
}
];
@ -100,4 +100,4 @@ class Modlogs extends Setting {
}
module.exports = Modlogs;
module.exports = ModerationLogsSetting;

View File

@ -30,7 +30,7 @@ class MuteSetting extends Setting {
default: true
}
],
usage: '[test] <what>',
usage: '[type|role|create] [muted-role|mute-type]',
examples: [
'muterole Muted',
'mutetype 1',

View File

@ -1,5 +1,13 @@
const { Setting } = require('../../../../interfaces/');
const Constants = {
Types: {
'discord': ['discord'],
'grant': ['grantable', 'grant', 'grants'],
'both': ['combined, both']
}
};
class PermissionTypeSetting extends Setting {
constructor(client) {
@ -7,13 +15,17 @@ class PermissionTypeSetting extends Setting {
super(client, {
name: 'permissionType',
module: 'utility',
aliases: ['permission'],
aliases: ['permission', 'permissionTypes', 'permissions', 'perm'],
usage: "[permission-type]",
guarded: true,
resolve: 'GUILD',
default: {
permissionType: 2
permissionType: 'both'
},
custom: true
examples: [
'permissiontype [discord|grant|both]',
'permissiontype reset'
]
});
this.client = client;
@ -22,22 +34,23 @@ class PermissionTypeSetting extends Setting {
async handle(message, params) {
const [prefix] = params;
const parameters = params.join(' ').toLowerCase();
const MaxCharacters = 6;
if(prefix.length > MaxCharacters) return {
msg: message.format('S_GUILDPREFIX_LENGTH', { length: prefix.length, max: MaxCharacters }),
let type = null;
for(const [ key, value ] of Object.entries(Constants.Types)) {
if(value.includes(parameters)) type = key;
}
if(!type) return {
msg: message.format('S_PERMISSIONTYPE_INVALIDTYPE'),
error: true
};
if(prefix.includes(' ')) return {
msg: message.format('S_GUILDPREFIX_SPACES'),
error: true
};
await message.guild._updateSettings({ [this.index]: type });
await message.guild._updateSettings({ [this.index]: prefix });
const description = message.format('S_PERMISSIONTYPE_DESCRIPTIONS', { type }, true);
return {
msg: message.format('S_GUILDPREFIX_SUCCESS', { prefix }),
msg: `${message.format('S_PERMISSIONTYPE_SUCCESS', { type, description })}`,
error: false
};
@ -46,8 +59,8 @@ class PermissionTypeSetting extends Setting {
fields(guild) {
return [
{
name: '》Prefix',
value: `\`${guild.prefix}\``
name: '》Permission Type',
value: `\`${guild._settings.permissionType}\``
}
];
}
@ -55,11 +68,3 @@ class PermissionTypeSetting extends Setting {
}
module.exports = PermissionTypeSetting;
const Constants = { //eslint-disable-line no-unused-vars
Types: {
'discord': 0,
'grants': 1,
'both': 2
}
};

View File

@ -168,7 +168,8 @@ const Guild = Structures.extend('Guild', (Guild) => {
}
get prefix() {
return this._settings.prefix;
return this._settings.prefix
|| this.client._options.bot.prefix;
}
}

View File

@ -27,7 +27,7 @@ const Message = Structures.extend('Message', (Message) => {
let language = 'en_us';
if(this.guild && this.guild._settings.locale) language = this.guild._settings.locale;
parameters.prefix = this.guild?.prefix || this.client._options.bot.prefix;
parameters.prefix = this.guild?.prefix;
let template = this.client.localeLoader.template(language, index); //.languages[language][index];
if(!template) {
@ -52,7 +52,7 @@ const Message = Structures.extend('Message', (Message) => {
async resolve() {
if (this.command.showUsage && !this.parameters.length) {
if (this.command.showUsage && !this.parameters.length && !Object.values(this.args).length) {
return this._showUsage();
}
@ -125,8 +125,7 @@ const Message = Structures.extend('Message', (Message) => {
? comp
: this.command;
const prefix = this.guild?.prefix
|| this.client._options.bot.prefix;
const prefix = this.guild?.prefix;
let fields = [];
if(component.examples.length > 0) {