forked from Galactic/galactic-bot
Merge branch 'message-commands' into slash-commands
This commit is contained in:
commit
a88cb49c56
@ -5,7 +5,7 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node index.js",
|
"start": "node index.js",
|
||||||
"dev": "node --trace-warnings --unhandled-rejections=strict index.js",
|
"dev": "nodemon --delay 10 --trace-warnings --unhandled-rejections=strict index.js",
|
||||||
"debug": "node --trace-warnings --inspect index.js",
|
"debug": "node --trace-warnings --inspect index.js",
|
||||||
"update": "git pull && cd api && yarn update",
|
"update": "git pull && cd api && yarn update",
|
||||||
"test": "jest --detectOpenHandles",
|
"test": "jest --detectOpenHandles",
|
||||||
|
@ -416,6 +416,8 @@
|
|||||||
"seamen",
|
"seamen",
|
||||||
"coming",
|
"coming",
|
||||||
"seaman",
|
"seaman",
|
||||||
|
"seus",
|
||||||
|
"seuss",
|
||||||
"rock",
|
"rock",
|
||||||
"dock",
|
"dock",
|
||||||
"lock",
|
"lock",
|
||||||
|
@ -44,6 +44,9 @@ Global permissions
|
|||||||
[COMMAND_PERMISSIONS_SHOW_TITLE]
|
[COMMAND_PERMISSIONS_SHOW_TITLE]
|
||||||
Granted permissions
|
Granted permissions
|
||||||
|
|
||||||
|
[COMMAND_PERMISSIONS_DESC]
|
||||||
|
Showing permissions {forin} **{target}**
|
||||||
|
|
||||||
[COMMAND_PERMISSIONS_NO_PERMS]
|
[COMMAND_PERMISSIONS_NO_PERMS]
|
||||||
No permissions granted
|
No permissions granted
|
||||||
|
|
||||||
|
@ -71,6 +71,9 @@ It seems like the mute role was deleted, use the command `-set mute` for more in
|
|||||||
[COMMAND_MUTE_MISSING_MODERATE_PERM]
|
[COMMAND_MUTE_MISSING_MODERATE_PERM]
|
||||||
Missing permissions to timeout users (Moderate Member)
|
Missing permissions to timeout users (Moderate Member)
|
||||||
|
|
||||||
|
[COMMAND_MUTE_HIERARCHY_ERROR]
|
||||||
|
the bot cannot timeout a user above its highest role
|
||||||
|
|
||||||
[COMMAND_MUTE_MISSING_MANAGEROLE_PERM]
|
[COMMAND_MUTE_MISSING_MANAGEROLE_PERM]
|
||||||
Missing permissions to manage roles.
|
Missing permissions to manage roles.
|
||||||
|
|
||||||
@ -303,6 +306,10 @@ the provided role(s) are higher than the bot, I cannot add them
|
|||||||
the provided role(s) are not on the grantable list
|
the provided role(s) are not on the grantable list
|
||||||
|
|
||||||
//History Command
|
//History Command
|
||||||
|
[COMMAND_HISTORY_HELP]
|
||||||
|
Display moderation history in the server.
|
||||||
|
Narrow the search down by using the parameters below.
|
||||||
|
|
||||||
[COMMAND_HISTORY_HISTORY]
|
[COMMAND_HISTORY_HISTORY]
|
||||||
Display moderation history for the server or for certain users.
|
Display moderation history for the server or for certain users.
|
||||||
|
|
||||||
@ -332,6 +339,9 @@ Failed to display cases in one embed, try a smaller page size.
|
|||||||
for {targets}
|
for {targets}
|
||||||
//target{plural}:
|
//target{plural}:
|
||||||
|
|
||||||
|
[COMMAND_HISTORY_SUCCESSMODERATOR]
|
||||||
|
by {moderator}
|
||||||
|
|
||||||
[COMMAND_HISTORY_NO_EXPORT_PERMS]
|
[COMMAND_HISTORY_NO_EXPORT_PERMS]
|
||||||
Must be admin to export moderation history.
|
Must be admin to export moderation history.
|
||||||
|
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
[COMMAND_PING_HELP]
|
||||||
|
Check if the bot is online.
|
||||||
|
|
||||||
|
[COMMAND_AVATAR_HELP]
|
||||||
|
Display a user's avatar.
|
||||||
|
Use the member option to display their server avatar.
|
||||||
|
|
||||||
[COMMAND_AVATAR_FORMATERROR]
|
[COMMAND_AVATAR_FORMATERROR]
|
||||||
Unable to find an avatar with those arguments, try a different size or format.
|
Unable to find an avatar with those arguments, try a different size or format.
|
||||||
|
|
||||||
@ -37,6 +44,8 @@ You have no active reminders.
|
|||||||
The content in your reminder was filtered.
|
The content in your reminder was filtered.
|
||||||
|
|
||||||
// Poll command
|
// Poll command
|
||||||
|
[COMMAND_POLL_HELP]
|
||||||
|
Have the bot send a poll message in a channel with an optional duration.
|
||||||
|
|
||||||
[COMMAND_POLL_QUESTIONS]
|
[COMMAND_POLL_QUESTIONS]
|
||||||
Please respond with question {number}.
|
Please respond with question {number}.
|
||||||
|
@ -20,6 +20,9 @@ Required Permissions
|
|||||||
Command takes no arguments
|
Command takes no arguments
|
||||||
|
|
||||||
// Generic setting field names
|
// Generic setting field names
|
||||||
|
[GENERAL_PREFIX]
|
||||||
|
》 Prefix
|
||||||
|
|
||||||
[GENERAL_STATUS]
|
[GENERAL_STATUS]
|
||||||
》 Status
|
》 Status
|
||||||
|
|
||||||
@ -131,3 +134,11 @@ switch({toggle}) {
|
|||||||
'off';
|
'off';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[FOR_IN_TOGGLE]
|
||||||
|
switch({toggle}) {
|
||||||
|
case true:
|
||||||
|
'for'; break;
|
||||||
|
case false:
|
||||||
|
'in'; break;
|
||||||
|
}
|
@ -26,4 +26,4 @@ The command **{command}** requires the __bot__ to have permissions to use.
|
|||||||
The command **{command}** can only be run by developers.
|
The command **{command}** can only be run by developers.
|
||||||
|
|
||||||
[INHIBITOR_GUILDONLY_ERROR]
|
[INHIBITOR_GUILDONLY_ERROR]
|
||||||
The command **{command}** is only available in servers.
|
The command **{command}** is only available in servers.
|
@ -7,6 +7,9 @@ You can increase the amount of targets by upgrading to premium.
|
|||||||
[INFRACTION_ERROR]
|
[INFRACTION_ERROR]
|
||||||
an error occured
|
an error occured
|
||||||
|
|
||||||
|
[INFRACTION_PROTECTIONPOSITIONERROR_SAME]
|
||||||
|
they have the same role position as you
|
||||||
|
|
||||||
[INFRACTION_PROTECTIONPOSITIONERROR]
|
[INFRACTION_PROTECTIONPOSITIONERROR]
|
||||||
they have hierarchy over you
|
they have hierarchy over you
|
||||||
|
|
||||||
|
@ -5,15 +5,24 @@ This is an issue that should be reported to a bot developer.
|
|||||||
[O_COMMANDHANDLER_GUILDONLY]
|
[O_COMMANDHANDLER_GUILDONLY]
|
||||||
This command can only be run in servers.
|
This command can only be run in servers.
|
||||||
|
|
||||||
|
[O_COMMANDHANDLER_GUILDONLY_OPT]
|
||||||
|
The option `{option}` is only valid in servers.
|
||||||
|
|
||||||
[O_COMMANDHANDLER_TYPEINTEGER]
|
[O_COMMANDHANDLER_TYPEINTEGER]
|
||||||
The command option {option} requires an integer between `{min}` and `{max}`.
|
The command option {option} requires an integer between `{min}` and `{max}`.
|
||||||
|
|
||||||
|
[O_COMMANDHANDLER_TYPEBOOLEAN]
|
||||||
|
The command option {option} requires a boolean resolveable (e.g. anything that can be interpreted as true or false)
|
||||||
|
|
||||||
[O_COMMANDHANDLER_TYPECOMMANDS]
|
[O_COMMANDHANDLER_TYPECOMMANDS]
|
||||||
The command option {option} requires command resolveables (e.g. `command:ping`, `command:history`)
|
The command option {option} requires command resolveables (e.g. `command:ping`, `command:history`)
|
||||||
|
|
||||||
[O_COMMANDHANDLER_TYPECOMMAND]
|
[O_COMMANDHANDLER_TYPECOMMAND]
|
||||||
The command option {option} requires a command resolveable (e.g. `command:ping`)
|
The command option {option} requires a command resolveable (e.g. `command:ping`)
|
||||||
|
|
||||||
|
[O_COMMANDHANDLER_TYPEMODULE]
|
||||||
|
The command option {option} requires a module resolveable (e.g. moderation)
|
||||||
|
|
||||||
[O_COMMANDHANDLER_TYPESTRING]
|
[O_COMMANDHANDLER_TYPESTRING]
|
||||||
The command option {option} requires a string.
|
The command option {option} requires a string.
|
||||||
|
|
||||||
@ -23,6 +32,9 @@ The command option {option} requires a date in the format `YYYY/MM/DD`
|
|||||||
[O_COMMANDHANDLER_TYPETIME]
|
[O_COMMANDHANDLER_TYPETIME]
|
||||||
The command option {option} requires a timestring (e.g. 5 min, 2w).
|
The command option {option} requires a timestring (e.g. 5 min, 2w).
|
||||||
|
|
||||||
|
[O_COMMANDHANDLER_TYPEUSER]
|
||||||
|
The command option {option} requires a user.
|
||||||
|
|
||||||
[O_COMMANDHANDLER_TYPEUSERS]
|
[O_COMMANDHANDLER_TYPEUSERS]
|
||||||
The command option {option} requires users.
|
The command option {option} requires users.
|
||||||
|
|
||||||
@ -80,3 +92,14 @@ Command Error
|
|||||||
[O_COMMANDHANDLER_COMMAND_NORESPONSE]
|
[O_COMMANDHANDLER_COMMAND_NORESPONSE]
|
||||||
Command returned no response. This should not happen and is likely a bug.
|
Command returned no response. This should not happen and is likely a bug.
|
||||||
|
|
||||||
|
[O_COMMANDHANDLER_UNRECOGNISED_FLAG]
|
||||||
|
Unrecognised flag: `{flag}`
|
||||||
|
See command help for valid flags.
|
||||||
|
|
||||||
|
[O_COMMANDHANDLER_UNRECOGNISED_OPTIONS]
|
||||||
|
Unrecognised options: `{opts}`
|
||||||
|
See command help for valid options.
|
||||||
|
|
||||||
|
[O_COMMANDHANDLER_INVALID_CHOICE]
|
||||||
|
`{value}` is an invalid choice for **{option}**.
|
||||||
|
Valid choices are `{choices}`.
|
@ -1,3 +1,6 @@
|
|||||||
|
[SETTING_TEXTCOMMANDS_HELP]
|
||||||
|
Enable or disable text commands or change the prefix.
|
||||||
|
|
||||||
[SETTING_PERMISSIONS_HELP]
|
[SETTING_PERMISSIONS_HELP]
|
||||||
Configure which set of permissions the bot works with.
|
Configure which set of permissions the bot works with.
|
||||||
|
|
||||||
|
@ -94,15 +94,17 @@ class ApiClientUtil {
|
|||||||
|
|
||||||
const { guildId } = message;
|
const { guildId } = message;
|
||||||
const evalFunc = (client, { guildId }) => {
|
const evalFunc = (client, { guildId }) => {
|
||||||
const guild = client.guilds.cache.get(guildId);
|
try {
|
||||||
if (!guild) return null;
|
const wrapper = client.getGuildWrapper(guildId);
|
||||||
const wrapper = new client.wrapperClasses.GuildWrapper(client, guild);
|
return wrapper.toJSON();
|
||||||
return wrapper.toJSON();
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.client.logger.debug(`guild-live request - shard: ${message.shard}, message id ${message.id}`);
|
this.client.logger.debug(`guild-live request - shard: ${message.shard}, message id ${message.id}`);
|
||||||
const result = await this.client.shardingManager.broadcastEval(evalFunc, { context: { guildId } });
|
const result = await this.client.shardingManager.broadcastEval(evalFunc, { context: { guildId } });
|
||||||
const guild = result.find((elem) => elem !== undefined);
|
const guild = result.find((elem) => elem !== null);
|
||||||
return guild;
|
return guild;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ class Logger {
|
|||||||
|
|
||||||
const maximumCharacters = Math.max(...Constants.Types.map((t) => t.length));
|
const maximumCharacters = Math.max(...Constants.Types.map((t) => t.length));
|
||||||
const spacers = maximumCharacters - type.length;
|
const spacers = maximumCharacters - type.length;
|
||||||
const text = `${chalk[color](type)}${" ".repeat(spacers)} ${header} : ${string}`;
|
const text = `${chalk[color](type)}${" ".repeat(spacers)} ${header}: ${string}`;
|
||||||
const strippedText = text.replace(stripRegex, '');
|
const strippedText = text.replace(stripRegex, '');
|
||||||
|
|
||||||
console.log(text); //eslint-disable-line no-console
|
console.log(text); //eslint-disable-line no-console
|
||||||
@ -86,6 +86,7 @@ class Logger {
|
|||||||
|
|
||||||
webhook(text, type) {
|
webhook(text, type) {
|
||||||
|
|
||||||
|
if (!this._webhook) return;
|
||||||
const message = text.replace(new RegExp(process.env.DISCORD_TOKEN, 'gu'), '<redacted>')
|
const message = text.replace(new RegExp(process.env.DISCORD_TOKEN, 'gu'), '<redacted>')
|
||||||
.replace(new RegExp(username, 'gu'), '<redacted>');
|
.replace(new RegExp(username, 'gu'), '<redacted>');
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ const { Routes } = require('discord-api-types/v9');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const hash = require('object-hash');
|
const hash = require('object-hash');
|
||||||
|
const { inspect } = require('util');
|
||||||
|
|
||||||
class SlashCommandManager {
|
class SlashCommandManager {
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ class SlashCommandManager {
|
|||||||
this.client.logger.write('info', `Commands hash: ${cmdHash}, ${guilds.length} out of date`);
|
this.client.logger.write('info', `Commands hash: ${cmdHash}, ${guilds.length} out of date`);
|
||||||
if (!guilds.length) return;
|
if (!guilds.length) return;
|
||||||
const promises = [];
|
const promises = [];
|
||||||
//console.log(JSON.stringify(commands));
|
//fs.writeFileSync(path.join(process.cwd(), 'commands.json'), JSON.stringify(commands));
|
||||||
for(const guild of guilds) {
|
for(const guild of guilds) {
|
||||||
promises.push(this.rest.put(
|
promises.push(this.rest.put(
|
||||||
Routes.applicationGuildCommands(clientId, guild),
|
Routes.applicationGuildCommands(clientId, guild),
|
||||||
@ -72,6 +73,10 @@ class SlashCommandManager {
|
|||||||
str += `${command.name}: `;
|
str += `${command.name}: `;
|
||||||
const options = Object.keys(invalid[key].options);
|
const options = Object.keys(invalid[key].options);
|
||||||
for (const optKey of options) {
|
for (const optKey of options) {
|
||||||
|
if (!command.options[optKey]) {
|
||||||
|
this.client.logger.warn(`Missing properties for ${command.name}: ${optKey}\nOptions: ${inspect(command.options)}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
str += `${command.options[optKey].name}\t`;
|
str += `${command.options[optKey].name}\t`;
|
||||||
}
|
}
|
||||||
str += `\n\n`;
|
str += `\n\n`;
|
||||||
|
@ -91,8 +91,8 @@ class DiscordClient extends Client {
|
|||||||
// this.logger.error(`Uncaught exception:\n${err.stack || err}`);
|
// this.logger.error(`Uncaught exception:\n${err.stack || err}`);
|
||||||
// });
|
// });
|
||||||
|
|
||||||
process.on('unhandledRejection', (err, reason) => {
|
process.on('unhandledRejection', (err) => {
|
||||||
this.logger.error(`Unhandled rejection:\n${err?.stack || err}\n${inspect(reason)}`);
|
this.logger.error(`Unhandled rejection:\n${err?.stack || err}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('message', this._handleMessage.bind(this));
|
process.on('message', this._handleMessage.bind(this));
|
||||||
@ -309,6 +309,14 @@ class DiscordClient extends Client {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format(index, params = {}, opts = {}) {
|
||||||
|
const {
|
||||||
|
code = false,
|
||||||
|
language = 'en_gb'
|
||||||
|
} = opts;
|
||||||
|
return this.localeLoader.format(language, index, params, code);
|
||||||
|
}
|
||||||
|
|
||||||
getGuildWrapper(id) {
|
getGuildWrapper(id) {
|
||||||
|
|
||||||
if (this.guildWrappers.has(id)) return this.guildWrappers.get(id);
|
if (this.guildWrappers.has(id)) return this.guildWrappers.get(id);
|
||||||
|
@ -37,7 +37,7 @@ class RateLimiter {
|
|||||||
|
|
||||||
if (!channel || !(channel instanceof TextChannel)) reject(new Error('Missing channel'));
|
if (!channel || !(channel instanceof TextChannel)) reject(new Error('Missing channel'));
|
||||||
if (!message || !(message instanceof Message)) reject(new Error('Missing message'));
|
if (!message || !(message instanceof Message)) reject(new Error('Missing message'));
|
||||||
if (!channel.permissionsFor(channel.guild.members.me).has('ManageMessages')) reject(new Error('Missing permission ManageMessages'));
|
if (!channel.permissionsFor(this.client.user).has('ManageMessages')) reject(new Error('Missing permission ManageMessages'));
|
||||||
|
|
||||||
if (!this.deleteQueue[channel.id]) this.deleteQueue[channel.id] = [];
|
if (!this.deleteQueue[channel.id]) this.deleteQueue[channel.id] = [];
|
||||||
this.deleteQueue[channel.id].push({ message, resolve, reject });
|
this.deleteQueue[channel.id].push({ message, resolve, reject });
|
||||||
@ -106,7 +106,7 @@ class RateLimiter {
|
|||||||
|
|
||||||
if (!channel || !(channel instanceof TextChannel)) reject(new Error('Missing channel.'));
|
if (!channel || !(channel instanceof TextChannel)) reject(new Error('Missing channel.'));
|
||||||
if (!message || !message.length) reject(new Error('Missing message.'));
|
if (!message || !message.length) reject(new Error('Missing message.'));
|
||||||
if (!channel.permissionsFor(channel.guild.members.me).has('SendMessages')) reject(new Error('Missing permission SendMessages'));
|
if (!channel.permissionsFor(this.client.user).has('SendMessages')) reject(new Error('Missing permission SendMessages'));
|
||||||
|
|
||||||
//Initiate queue
|
//Initiate queue
|
||||||
if (!this.sendQueue[channel.id]) this.sendQueue[channel.id] = [];
|
if (!this.sendQueue[channel.id]) this.sendQueue[channel.id] = [];
|
||||||
@ -173,7 +173,7 @@ class RateLimiter {
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!channel || !(channel instanceof TextChannel)) reject(new Error('Missing channel'));
|
if (!channel || !(channel instanceof TextChannel)) reject(new Error('Missing channel'));
|
||||||
if (!channel.permissionsFor(channel.guild.members.me).has('SendMessages')) reject(new Error('Missing permission SendMessages'));
|
if (!channel.permissionsFor(this.client.user).has('SendMessages')) reject(new Error('Missing permission SendMessages'));
|
||||||
if (!message) reject(new Error('Missing message'));
|
if (!message) reject(new Error('Missing message'));
|
||||||
if (limit === null) limit = 15;
|
if (limit === null) limit = 15;
|
||||||
|
|
||||||
|
@ -346,7 +346,7 @@ class Resolver {
|
|||||||
|
|
||||||
const match = resolveable.match(id);
|
const match = resolveable.match(id);
|
||||||
const [, ch] = match;
|
const [, ch] = match;
|
||||||
const channel = await this.client.channels.fetch(ch).catch((e) => { }); //eslint-disable-line no-empty, no-empty-function, no-unused-vars
|
const channel = await CM.fetch(ch).catch((e) => { }); //eslint-disable-line no-empty, no-empty-function, no-unused-vars
|
||||||
if (channel && filter(channel)) resolved.push(channel);
|
if (channel && filter(channel)) resolved.push(channel);
|
||||||
|
|
||||||
} else if (name.test(resolveable)) {
|
} else if (name.test(resolveable)) {
|
||||||
|
@ -72,7 +72,7 @@ class GuildWrapper {
|
|||||||
startedIn = await this.resolveChannel(startedIn);
|
startedIn = await this.resolveChannel(startedIn);
|
||||||
const pollChannel = await this.resolveChannel(channel);
|
const pollChannel = await this.resolveChannel(channel);
|
||||||
if (pollChannel) {
|
if (pollChannel) {
|
||||||
const msg = await pollChannel.messages.fetch(message);
|
const msg = await pollChannel.messages.fetch(message).catch(() => null);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
const { reactions } = msg;
|
const { reactions } = msg;
|
||||||
const reactionEmojis = questions.length ? PollReactions.Multi : PollReactions.Single;
|
const reactionEmojis = questions.length ? PollReactions.Multi : PollReactions.Single;
|
||||||
@ -360,7 +360,7 @@ class GuildWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get prefix() {
|
get prefix() {
|
||||||
return this._settings.prefix || this.client.prefix;
|
return this._settings.textcommands.prefix || this.client.prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
get available() {
|
get available() {
|
||||||
|
@ -217,7 +217,7 @@ class InteractionWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isContextMenu() {
|
isContextMenu() {
|
||||||
return this.interaction.isContextMenu();
|
return this.interaction.isContextMenuCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
isSelectMenu() {
|
isSelectMenu() {
|
||||||
|
@ -118,7 +118,7 @@ class InvokerWrapper {
|
|||||||
disableMentions: opts.disableMentions
|
disableMentions: opts.disableMentions
|
||||||
};
|
};
|
||||||
|
|
||||||
if (opts.editReply) await this.editReply(data);
|
if (opts.editReply || this.deferred) await this.editReply(data);
|
||||||
else await this.reply(data) //this.channel.send(data)
|
else await this.reply(data) //this.channel.send(data)
|
||||||
.then((msg) => {
|
.then((msg) => {
|
||||||
if (opts.delete) msg.delete();
|
if (opts.delete) msg.delete();
|
||||||
|
@ -90,6 +90,7 @@ class MessageWrapper {
|
|||||||
|
|
||||||
async editReply(options) {
|
async editReply(options) {
|
||||||
if (!this._reply) throw new Error('Message not replied to');
|
if (!this._reply) throw new Error('Message not replied to');
|
||||||
|
if (!options.allowedMentions) options.allowedMentions = { repliedUser: false }; // Disables the mention in the inline reply
|
||||||
return this._reply.edit(options);
|
return this._reply.edit(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ class AdministrationModule extends SettingsCommand {
|
|||||||
constructor(client) {
|
constructor(client) {
|
||||||
super(client, {
|
super(client, {
|
||||||
name: 'administration',
|
name: 'administration',
|
||||||
|
aliases: ['admin'],
|
||||||
description: 'Configure the administrative settings',
|
description: 'Configure the administrative settings',
|
||||||
module: 'administration'
|
module: 'administration'
|
||||||
});
|
});
|
||||||
|
@ -39,7 +39,8 @@ class ImportCommand extends SlashCommand {
|
|||||||
}, {
|
}, {
|
||||||
name: 'overwrite',
|
name: 'overwrite',
|
||||||
description: 'Whether any existing logs should be overwritten by the imports. By default new ones are bumped',
|
description: 'Whether any existing logs should be overwritten by the imports. By default new ones are bumped',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN',
|
||||||
|
flag: true, valueOptional: true, defaultValue: true
|
||||||
}]
|
}]
|
||||||
}],
|
}],
|
||||||
clientPermissions: ['ManageWebhooks']
|
clientPermissions: ['ManageWebhooks']
|
||||||
|
@ -46,7 +46,7 @@ class ModstatsCommand extends SlashCommand {
|
|||||||
|
|
||||||
const data = await this.client.mongodb.infractions.find(query, { projection: { executor: 1, type: 1 } });
|
const data = await this.client.mongodb.infractions.find(query, { projection: { executor: 1, type: 1 } });
|
||||||
for (const log of data) {
|
for (const log of data) {
|
||||||
if (log.executor === guild.members.me.id) continue;
|
if (log.executor === this.client.user.id) continue;
|
||||||
if (!result[log.executor]) {
|
if (!result[log.executor]) {
|
||||||
const user = await this.client.resolveUser(log.executor);
|
const user = await this.client.resolveUser(log.executor);
|
||||||
result[log.executor] = { name: user.tag };
|
result[log.executor] = { name: user.tag };
|
||||||
|
@ -27,7 +27,8 @@ class PermissionsCommand extends SlashCommand {
|
|||||||
name: 'channel',
|
name: 'channel',
|
||||||
description: 'The channel(s) in which this permission is granted to user or role',
|
description: 'The channel(s) in which this permission is granted to user or role',
|
||||||
type: 'TEXT_CHANNELS',
|
type: 'TEXT_CHANNELS',
|
||||||
dependsOn: ['permission']
|
dependsOn: ['permission'],
|
||||||
|
flag: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'role',
|
name: 'role',
|
||||||
@ -64,6 +65,7 @@ class PermissionsCommand extends SlashCommand {
|
|||||||
name: 'channel',
|
name: 'channel',
|
||||||
description: 'The channel(s) to reset',
|
description: 'The channel(s) to reset',
|
||||||
type: 'TEXT_CHANNELS',
|
type: 'TEXT_CHANNELS',
|
||||||
|
flag: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'role',
|
name: 'role',
|
||||||
@ -233,6 +235,7 @@ class PermissionsCommand extends SlashCommand {
|
|||||||
|
|
||||||
const fields = [];
|
const fields = [];
|
||||||
let update = false;
|
let update = false;
|
||||||
|
const target = member?.value || role?.value || channel?.value;
|
||||||
|
|
||||||
if (member || role) {
|
if (member || role) {
|
||||||
|
|
||||||
@ -340,6 +343,7 @@ class PermissionsCommand extends SlashCommand {
|
|||||||
|
|
||||||
if(!fields.length) return { index: 'COMMAND_PERMISSIONS_NO_PERMS' };
|
if(!fields.length) return { index: 'COMMAND_PERMISSIONS_NO_PERMS' };
|
||||||
const embed = {
|
const embed = {
|
||||||
|
description: target ? interaction.format('COMMAND_PERMISSIONS_DESC', { target: target.tag || target.name || 'any', forin: interaction.format('FOR_IN_TOGGLE', { toggle: target.type === undefined }, { code: true }) }) : '',
|
||||||
title: interaction.format('COMMAND_PERMISSIONS_SHOW_TITLE'),
|
title: interaction.format('COMMAND_PERMISSIONS_SHOW_TITLE'),
|
||||||
fields: [ ]
|
fields: [ ]
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { SlashCommand, CommandOption } = require("../../../interfaces");
|
const { SlashCommand } = require("../../../interfaces");
|
||||||
const { Util } = require('../../../../utilities');
|
const { Util } = require('../../../../utilities');
|
||||||
|
|
||||||
class SettingsCommand extends SlashCommand {
|
class SettingsCommand extends SlashCommand {
|
||||||
@ -10,11 +10,11 @@ class SettingsCommand extends SlashCommand {
|
|||||||
description: 'View settings',
|
description: 'View settings',
|
||||||
options: [
|
options: [
|
||||||
// Probably add reset options here too
|
// Probably add reset options here too
|
||||||
new CommandOption({
|
{
|
||||||
name: 'list',
|
name: 'list',
|
||||||
description: 'List available settings',
|
description: 'List available settings',
|
||||||
type: 'SUB_COMMAND'
|
type: 'SUB_COMMAND'
|
||||||
})
|
}
|
||||||
],
|
],
|
||||||
memberPermissions: ['ManageGuild']
|
memberPermissions: ['ManageGuild']
|
||||||
});
|
});
|
||||||
|
@ -13,16 +13,20 @@ class EvalCommand extends Command {
|
|||||||
name: 'eval',
|
name: 'eval',
|
||||||
aliases: ['e', 'evaluate'],
|
aliases: ['e', 'evaluate'],
|
||||||
restricted: true,
|
restricted: true,
|
||||||
module: 'developer'
|
module: 'developer',
|
||||||
|
options: [
|
||||||
|
{ name: 'code' },
|
||||||
|
{ name: 'async', flag: true, valueOptional: true, defaultValue: true }
|
||||||
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(invoker, { parameters: params }) {
|
async execute(invoker, { code, async }) {
|
||||||
|
|
||||||
const args = {}; // Temporary args until I figure out how I want to implement them
|
const args = {}; // Temporary args until I figure out how I want to implement them
|
||||||
|
|
||||||
params = params.join(' ');
|
let params = code.value;
|
||||||
if (args.async) params = `(async () => {${params}})()`;
|
if (async?.value) params = `(async () => {${params}})()`;
|
||||||
const { guild, author, member, client } = invoker; //eslint-disable-line no-unused-vars
|
const { guild, author, member, client } = invoker; //eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
let response = null;
|
let response = null;
|
||||||
|
@ -17,7 +17,8 @@ class StatsCommand extends SlashCommand {
|
|||||||
name: 'log',
|
name: 'log',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
types: ['FLAG'],
|
types: ['FLAG'],
|
||||||
description: 'Logs the output in the console.'
|
description: 'Logs the output in the console.',
|
||||||
|
flag: true, valueOptional: true, defaultValue: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
clientPermissions: ['SendMessages', 'EmbedLinks'],
|
clientPermissions: ['SendMessages', 'EmbedLinks'],
|
||||||
|
@ -15,7 +15,7 @@ class Commands extends SlashCommand {
|
|||||||
type: 'MODULE',
|
type: 'MODULE',
|
||||||
description: ['List commands from a specific module']
|
description: ['List commands from a specific module']
|
||||||
}],
|
}],
|
||||||
memberPermissions: ['ManageGuild'],
|
memberPermissions: [],
|
||||||
guildOnly: true
|
guildOnly: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@ class BanCommand extends ModerationCommand {
|
|||||||
type: 'INTEGER',
|
type: 'INTEGER',
|
||||||
description: 'How many days worth of messages to prune',
|
description: 'How many days worth of messages to prune',
|
||||||
minimum: 1,
|
minimum: 1,
|
||||||
maximum: 7
|
maximum: 7,
|
||||||
|
flag: true
|
||||||
}, {
|
}, {
|
||||||
name: 'users',
|
name: 'users',
|
||||||
type: 'USERS',
|
type: 'USERS',
|
||||||
|
@ -23,7 +23,8 @@ class CaseCommand extends SlashCommand {
|
|||||||
'Print out more detailed information about the case',
|
'Print out more detailed information about the case',
|
||||||
'List changes to the case'
|
'List changes to the case'
|
||||||
],
|
],
|
||||||
depeondsOn: ['id']
|
depeondsOn: ['id'],
|
||||||
|
flag: true, valueOptional: true, defaultValue: true
|
||||||
}],
|
}],
|
||||||
guildOnly: true,
|
guildOnly: true,
|
||||||
showUsage: true,
|
showUsage: true,
|
||||||
|
@ -24,14 +24,15 @@ class EditCommand extends SlashCommand {
|
|||||||
name: 'points',
|
name: 'points',
|
||||||
type: 'INTEGER',
|
type: 'INTEGER',
|
||||||
description: 'New point value for case',
|
description: 'New point value for case',
|
||||||
minimum: 0, maximum: 100
|
minimum: 0, maximum: 100, flag: true
|
||||||
}, {
|
}, {
|
||||||
name: ['expiration', 'duration'],
|
name: ['expiration', 'duration'],
|
||||||
type: 'TIME',
|
type: 'TIME',
|
||||||
description: [
|
description: [
|
||||||
'New expiration for points, starts from the time the infraction was issued',
|
'New expiration for points, starts from the time the infraction was issued',
|
||||||
'Duration if the infraction is timed'
|
'Duration if the infraction is timed'
|
||||||
]
|
],
|
||||||
|
flag: true
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,8 @@ class HistoryCommand extends SlashCommand {
|
|||||||
options: [{
|
options: [{
|
||||||
name: ['before', 'after'],
|
name: ['before', 'after'],
|
||||||
type: 'DATE',
|
type: 'DATE',
|
||||||
description: 'Filter by a date, must be in YYYY/MM/DD or YYYY-MM-DD format'
|
description: 'Filter by a date, must be in YYYY/MM/DD or YYYY-MM-DD format',
|
||||||
|
flag: true
|
||||||
}, {
|
}, {
|
||||||
name: ['verbose', 'oldest', 'export', 'private'],
|
name: ['verbose', 'oldest', 'export', 'private'],
|
||||||
description: [
|
description: [
|
||||||
@ -33,26 +34,35 @@ class HistoryCommand extends SlashCommand {
|
|||||||
'Export the list of infractions',
|
'Export the list of infractions',
|
||||||
'DM the command response'
|
'DM the command response'
|
||||||
],
|
],
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN',
|
||||||
|
flag: true, valueOptional: true, defaultValue: true
|
||||||
}, {
|
}, {
|
||||||
name: 'type',
|
name: 'type',
|
||||||
description: 'Filter infractions by type',
|
description: 'Filter infractions by type',
|
||||||
choices: Infractions.map((inf) => {
|
choices: Infractions.map((inf) => {
|
||||||
return { name: inf.toLowerCase(), value: inf };
|
return { name: inf.toLowerCase(), value: inf };
|
||||||
})
|
}),
|
||||||
|
flag: true
|
||||||
}, {
|
}, {
|
||||||
name: ['pagesize', 'page'],
|
name: ['pagesize', 'page'],
|
||||||
description: ['Amount of infractions to list per page', 'Page to select'],
|
description: ['Amount of infractions to list per page', 'Page to select'],
|
||||||
type: 'INTEGER',
|
type: 'INTEGER',
|
||||||
minimum: 1
|
minimum: 1,
|
||||||
|
flag: true
|
||||||
}, {
|
}, {
|
||||||
name: ['user', 'moderator'], //
|
name: 'user',
|
||||||
description: ['User whose infractions to query, overrides channel if both are given', 'Query by moderator'],
|
description: 'User whose infractions to query, overrides channel if both are given',
|
||||||
type: 'USER'
|
type: 'USER'
|
||||||
|
}, {
|
||||||
|
name: 'moderator',
|
||||||
|
description: 'Query by moderator',
|
||||||
|
type: 'USER',
|
||||||
|
flag: true
|
||||||
}, {
|
}, {
|
||||||
name: 'channel',
|
name: 'channel',
|
||||||
description: 'Infractions done on channels, e.g. slowmode, lockdown',
|
description: 'Infractions done on channels, e.g. slowmode, lockdown',
|
||||||
type: 'TEXT_CHANNEL'
|
type: 'TEXT_CHANNEL',
|
||||||
|
flag: true
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -95,6 +105,7 @@ class HistoryCommand extends SlashCommand {
|
|||||||
limit: pageSize
|
limit: pageSize
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const me = await guild.resolveMember(this.client.user);
|
||||||
const embed = {
|
const embed = {
|
||||||
author: {
|
author: {
|
||||||
name: 'Infraction History',
|
name: 'Infraction History',
|
||||||
@ -104,7 +115,7 @@ class HistoryCommand extends SlashCommand {
|
|||||||
footer: {
|
footer: {
|
||||||
text: `• Page ${_page}/${maxPage} | ${resultsAmt} Results`
|
text: `• Page ${_page}/${maxPage} | ${resultsAmt} Results`
|
||||||
},
|
},
|
||||||
color: invoker.guild.members.me.roles.highest.color
|
color: me.roles.highest.color
|
||||||
};
|
};
|
||||||
|
|
||||||
if (invoker.guild._settings.modpoints.enabled) {
|
if (invoker.guild._settings.modpoints.enabled) {
|
||||||
@ -180,12 +191,18 @@ class HistoryCommand extends SlashCommand {
|
|||||||
|
|
||||||
const type = invoker.format('COMMAND_HISTORY_SUCCESSTYPE', { old: oldest?.value || false }, { code: true });
|
const type = invoker.format('COMMAND_HISTORY_SUCCESSTYPE', { old: oldest?.value || false }, { code: true });
|
||||||
try {
|
try {
|
||||||
|
let targets = '';
|
||||||
|
if (user || channel) targets = invoker.format('COMMAND_HISTORY_SUCCESSTARGETS', {
|
||||||
|
//plural: parsed.length === 1 ? '' : 's',
|
||||||
|
targets: `**${Util.escapeMarkdown(user?.value.tag || channel?.value.name)}**` //parsed.map((p) => `**${Util.escapeMarkdown(p.display)}**`).join(' ')
|
||||||
|
});
|
||||||
|
else if (moderator) targets = invoker.format('COMMAND_HISTORY_SUCCESSMODERATOR', {
|
||||||
|
moderator: `**${Util.escapeMarkdown(moderator.value.tag)}**`
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: invoker.format('COMMAND_HISTORY_SUCCESS', {
|
content: invoker.format('COMMAND_HISTORY_SUCCESS', {
|
||||||
targets: user || channel ? invoker.format('COMMAND_HISTORY_SUCCESSTARGETS', {
|
targets,
|
||||||
//plural: parsed.length === 1 ? '' : 's',
|
|
||||||
targets: `**${Util.escapeMarkdown(user?.value.tag || channel?.value.name)}**` //parsed.map((p) => `**${Util.escapeMarkdown(p.display)}**`).join(' ')
|
|
||||||
}) : '',
|
|
||||||
type
|
type
|
||||||
}),
|
}),
|
||||||
emoji: 'success',
|
emoji: 'success',
|
||||||
|
@ -27,8 +27,9 @@ class MuteCommand extends ModerationCommand {
|
|||||||
const { guild } = interaction;
|
const { guild } = interaction;
|
||||||
const settings = await guild.settings();
|
const settings = await guild.settings();
|
||||||
const { type } = settings.mute;
|
const { type } = settings.mute;
|
||||||
if (type === 3 && !guild.members.me.permissions.has('ModerateMembers')) throw new CommandError(interaction, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', params: { command: this.name, missing: 'ModerateMembers' } });
|
const me = await guild.resolveMember(this.client.user);
|
||||||
else if (!guild.members.me.permissions.has('ManageRoles')) throw new CommandError(interaction, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', params: { command: this.name, missing: 'ManageRoles' } });
|
if (type === 3 && !me.permissions.has('ModerateMembers')) throw new CommandError(interaction, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', params: { command: this.name, missing: 'ModerateMembers' } });
|
||||||
|
else if (!me.permissions.has('ManageRoles')) throw new CommandError(interaction, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', params: { command: this.name, missing: 'ManageRoles' } });
|
||||||
|
|
||||||
return this.client.moderationManager.handleInfraction(Mute, interaction, {
|
return this.client.moderationManager.handleInfraction(Mute, interaction, {
|
||||||
targets: users.value,
|
targets: users.value,
|
||||||
|
@ -12,7 +12,7 @@ class NicknameCommand extends ModerationCommand {
|
|||||||
name: 'name',
|
name: 'name',
|
||||||
description: 'The new nickname to give',
|
description: 'The new nickname to give',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
required: true
|
required: true, flag: true
|
||||||
}],
|
}],
|
||||||
memberPermissions: ['ManageNicknames'],
|
memberPermissions: ['ManageNicknames'],
|
||||||
clientPermissions: ['ManageNicknames'],
|
clientPermissions: ['ManageNicknames'],
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
const { ModerationCommand, CommandError } = require('../../../interfaces');
|
const { ModerationCommand, CommandError } = require('../../../interfaces');
|
||||||
const { Prune } = require('../../../infractions');
|
const { Prune } = require('../../../infractions');
|
||||||
|
|
||||||
|
const flag = true,
|
||||||
|
valueOptional = true,
|
||||||
|
defaultValue = true;
|
||||||
|
|
||||||
class PruneCommand extends ModerationCommand {
|
class PruneCommand extends ModerationCommand {
|
||||||
|
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
@ -26,56 +30,69 @@ class PruneCommand extends ModerationCommand {
|
|||||||
}, {
|
}, {
|
||||||
name: 'silent',
|
name: 'silent',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
description: 'Prune quietly'
|
description: 'Prune quietly',
|
||||||
|
flag, valueOptional, defaultValue
|
||||||
}, {
|
}, {
|
||||||
name: 'bots',
|
name: 'bots',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
description: 'Prune messages from bots'
|
description: 'Prune messages from bots',
|
||||||
|
flag, valueOptional, defaultValue
|
||||||
}, {
|
}, {
|
||||||
name: 'humans',
|
name: 'humans',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
description: 'Prune messages from humans'
|
description: 'Prune messages from humans',
|
||||||
|
flag, valueOptional, defaultValue
|
||||||
}, {
|
}, {
|
||||||
name: 'contains',
|
name: 'contains',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
description: 'Text to look for messages by'
|
description: 'Text to look for messages by',
|
||||||
|
flag
|
||||||
}, {
|
}, {
|
||||||
name: 'startswith',
|
name: 'startswith',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
description: 'Text the messages to delete start with'
|
description: 'Text the messages to delete start with',
|
||||||
|
flag
|
||||||
}, {
|
}, {
|
||||||
name: 'endswith',
|
name: 'endswith',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
description: 'Text the messages to delete end with'
|
description: 'Text the messages to delete end with',
|
||||||
|
flag
|
||||||
}, {
|
}, {
|
||||||
name: 'text',
|
name: 'text',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
description: 'Only delete messages containing text'
|
description: 'Only delete messages containing text',
|
||||||
|
flag, valueOptional, defaultValue
|
||||||
}, {
|
}, {
|
||||||
name: 'invites',
|
name: 'invites',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
description: 'Delete messages containing invites'
|
description: 'Delete messages containing invites',
|
||||||
|
flag, valueOptional, defaultValue
|
||||||
}, {
|
}, {
|
||||||
name: 'links',
|
name: 'links',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
description: 'Delete messages containing links'
|
description: 'Delete messages containing links',
|
||||||
|
flag, valueOptional, defaultValue
|
||||||
}, {
|
}, {
|
||||||
name: 'emojis',
|
name: 'emojis',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
description: 'Prune messages cotaining emojis'
|
description: 'Prune messages cotaining emojis',
|
||||||
|
flag, valueOptional, defaultValue
|
||||||
}, {
|
}, {
|
||||||
name: 'after',
|
name: 'after',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
description: 'ID of message after which to start deleting'
|
description: 'ID of message after which to start deleting',
|
||||||
|
flag
|
||||||
}, {
|
}, {
|
||||||
name: 'before',
|
name: 'before',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
description: 'ID of message before which to start deleting'
|
description: 'ID of message before which to start deleting',
|
||||||
|
flag
|
||||||
}, {
|
}, {
|
||||||
name: 'logic',
|
name: 'logic',
|
||||||
// type: '',
|
// type: '',
|
||||||
choices: [{ name: 'AND', value: 'AND' }, { name: 'OR', value: 'OR' }],
|
choices: [{ name: 'AND', value: 'AND' }, { name: 'OR', value: 'OR' }],
|
||||||
description: 'Logic type to use for combining options'
|
description: 'Logic type to use for combining options',
|
||||||
|
flag
|
||||||
}, {
|
}, {
|
||||||
name: 'reason',
|
name: 'reason',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
|
@ -22,7 +22,8 @@ class ResolveCommand extends SlashCommand {
|
|||||||
}, {
|
}, {
|
||||||
name: 'notify',
|
name: 'notify',
|
||||||
description: 'Attempt to notify the user about the resolve, may not always be possible',
|
description: 'Attempt to notify the user about the resolve, may not always be possible',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN',
|
||||||
|
flag: true, valueOptional: true, defaultValue: true
|
||||||
}] // Potentially add another option to enable a range of cases
|
}] // Potentially add another option to enable a range of cases
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class StaffCommand extends SlashCommand {
|
|||||||
// const role = await guild.resolveRole(staff.role);
|
// const role = await guild.resolveRole(staff.role);
|
||||||
// if(!role) return invoker.editReply({ index: 'COMMAND_STAFF_ERROR', emoji: 'failure' });
|
// if(!role) return invoker.editReply({ index: 'COMMAND_STAFF_ERROR', emoji: 'failure' });
|
||||||
|
|
||||||
await channel.send({
|
return channel.send({
|
||||||
content: guild.format('COMMAND_STAFF_SUMMON', { author: author.tag, role: staff.role }),
|
content: guild.format('COMMAND_STAFF_SUMMON', { author: author.tag, role: staff.role }),
|
||||||
allowedMentions: { parse: ['roles'] } // roles: [staff.role],
|
allowedMentions: { parse: ['roles'] } // roles: [staff.role],
|
||||||
});
|
});
|
||||||
|
@ -23,8 +23,9 @@ class UnmuteCommand extends ModerationCommand {
|
|||||||
const { guild } = interaction;
|
const { guild } = interaction;
|
||||||
const settings = await guild.settings();
|
const settings = await guild.settings();
|
||||||
const { type } = settings.mute;
|
const { type } = settings.mute;
|
||||||
if (type === 3 && !guild.members.me.permissions.has('ModerateMembers')) throw new CommandError(interaction, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', params: { command: this.name, missing: 'ModerateMembers' } });
|
const me = await guild.resolveMember(this.client.user);
|
||||||
else if (!guild.members.me.permissions.has('ManageRoles')) throw new CommandError(interaction, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', params: { command: this.name, missing: 'ManageRoles' } });
|
if (type === 3 && !me.permissions.has('ModerateMembers')) throw new CommandError(interaction, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', params: { command: this.name, missing: 'ModerateMembers' } });
|
||||||
|
else if (!me.permissions.has('ManageRoles')) throw new CommandError(interaction, { index: 'INHIBITOR_CLIENTPERMISSIONS_ERROR', params: { command: this.name, missing: 'ManageRoles' } });
|
||||||
|
|
||||||
return this.client.moderationManager.handleInfraction(Unmute, interaction, {
|
return this.client.moderationManager.handleInfraction(Unmute, interaction, {
|
||||||
targets: users.value,
|
targets: users.value,
|
||||||
|
@ -12,8 +12,9 @@ const { SlashCommand, Infraction } = require("../../../interfaces");
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class ResolveCommand extends SlashCommand {
|
class UnresolveCommand extends SlashCommand {
|
||||||
|
|
||||||
|
// TODO: make unresolving enact the infraction again
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
super(client, {
|
super(client, {
|
||||||
name: 'unresolve',
|
name: 'unresolve',
|
||||||
@ -50,4 +51,4 @@ class ResolveCommand extends SlashCommand {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ResolveCommand;
|
module.exports = UnresolveCommand;
|
@ -13,14 +13,16 @@ class AvatarCommand extends SlashCommand {
|
|||||||
// type: 'INTEGER',
|
// type: 'INTEGER',
|
||||||
choices: [16, 32, 64, 128, 256, 512, 1024, 2048].map((i) => {
|
choices: [16, 32, 64, 128, 256, 512, 1024, 2048].map((i) => {
|
||||||
return { name: `${i}`, value: `${i}` };
|
return { name: `${i}`, value: `${i}` };
|
||||||
})
|
}),
|
||||||
|
flag: true
|
||||||
}, {
|
}, {
|
||||||
name: 'format',
|
name: 'format',
|
||||||
description: 'Image format',
|
description: 'Image format',
|
||||||
// type: 'STRING'
|
// type: 'STRING'
|
||||||
choices: ['webp', 'png', 'jpeg', 'jpg', 'gif'].map((i) => {
|
choices: ['webp', 'png', 'jpeg', 'jpg', 'gif'].map((i) => {
|
||||||
return { name: i, value: i };
|
return { name: i, value: i };
|
||||||
})
|
}),
|
||||||
|
flag: true
|
||||||
}, {
|
}, {
|
||||||
name: 'user',
|
name: 'user',
|
||||||
description: 'Use this for the user\'s global avatar',
|
description: 'Use this for the user\'s global avatar',
|
||||||
@ -28,7 +30,8 @@ class AvatarCommand extends SlashCommand {
|
|||||||
}, {
|
}, {
|
||||||
name: 'member',
|
name: 'member',
|
||||||
description: 'Use this for the user\'s server avatar',
|
description: 'Use this for the user\'s server avatar',
|
||||||
type: 'MEMBER'
|
type: 'MEMBER',
|
||||||
|
flag: true
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ class PollCommand extends SlashCommand {
|
|||||||
const questions = [];
|
const questions = [];
|
||||||
|
|
||||||
const _channel = channel?.value || invoker.channel;
|
const _channel = channel?.value || invoker.channel;
|
||||||
const botMissing = _channel.permissionsFor(guild.members.me).missing(['SendMessages', 'EmbedLinks']);
|
const botMissing = _channel.permissionsFor(this.client.user).missing(['SendMessages', 'EmbedLinks']);
|
||||||
const userMissing = _channel.permissionsFor(member).missing(['SendMessages']);
|
const userMissing = _channel.permissionsFor(member).missing(['SendMessages']);
|
||||||
if (botMissing.length) return invoker.editReply({ index: 'COMMAND_POLL_BOT_PERMS', params: { missing: botMissing.join(', '), channel: _channel.id } });
|
if (botMissing.length) return invoker.editReply({ index: 'COMMAND_POLL_BOT_PERMS', params: { missing: botMissing.join(', '), channel: _channel.id } });
|
||||||
if (userMissing.length) return invoker.editReply({ index: 'COMMAND_POLL_USER_PERMS', params: { missing: userMissing.join(', '), channel: _channel.id } });
|
if (userMissing.length) return invoker.editReply({ index: 'COMMAND_POLL_USER_PERMS', params: { missing: userMissing.join(', '), channel: _channel.id } });
|
||||||
@ -65,10 +65,10 @@ class PollCommand extends SlashCommand {
|
|||||||
for (let i = 0; i < choices.value; i++) {
|
for (let i = 0; i < choices.value; i++) {
|
||||||
const response = await invoker.promptMessage({
|
const response = await invoker.promptMessage({
|
||||||
content: guild.format(`COMMAND_POLL_QUESTION${choices.value === 1 ? '' : 'S'}`, { number: i + 1 }) + '\n' + guild.format('COMMAND_POLL_ADDENDUM'),
|
content: guild.format(`COMMAND_POLL_QUESTION${choices.value === 1 ? '' : 'S'}`, { number: i + 1 }) + '\n' + guild.format('COMMAND_POLL_ADDENDUM'),
|
||||||
time: 90, editReply: true
|
time: 90, editReply: invoker.replied
|
||||||
});
|
});
|
||||||
if (!response || !response.content) return invoker.editReply({ index: 'COMMAND_POLL_TIMEOUT' });
|
if (!response || !response.content) return invoker.editReply({ index: 'COMMAND_POLL_TIMEOUT' });
|
||||||
if(invoker.channel.permissionsFor(guild.members.me).has('ManageMessages')) await response.delete().catch(() => null);
|
if(invoker.channel.permissionsFor(this.client.user).has('ManageMessages')) await response.delete().catch(() => null);
|
||||||
const { content } = response;
|
const { content } = response;
|
||||||
if (content.toLowerCase() === 'stop') break;
|
if (content.toLowerCase() === 'stop') break;
|
||||||
if (content.toLowerCase() === 'cancel') return invoker.editReply({ index: 'GENERAL_CANCELLED' });
|
if (content.toLowerCase() === 'cancel') return invoker.editReply({ index: 'GENERAL_CANCELLED' });
|
||||||
|
@ -34,7 +34,8 @@ class SelfroleCommand extends SlashCommand {
|
|||||||
const { guild, member } = invoker;
|
const { guild, member } = invoker;
|
||||||
const { selfrole } = await guild.settings();
|
const { selfrole } = await guild.settings();
|
||||||
if (!selfrole.roles.length) return { index: 'COMMAND_SELFROLE_NONE', emoji: 'failure' };
|
if (!selfrole.roles.length) return { index: 'COMMAND_SELFROLE_NONE', emoji: 'failure' };
|
||||||
const ownHighest = guild.members.me.roles.highest;
|
const me = await guild.resolveMember(this.client.user);
|
||||||
|
const ownHighest = me.roles.highest;
|
||||||
|
|
||||||
const memberRoles = member.roles.cache.map((r) => r.id);
|
const memberRoles = member.roles.cache.map((r) => r.id);
|
||||||
const tooHigh = roles?.value.filter((r) => r.position > ownHighest.position);
|
const tooHigh = roles?.value.filter((r) => r.position > ownHighest.position);
|
||||||
|
@ -13,7 +13,7 @@ class ClientPermissions extends Inhibitor {
|
|||||||
|
|
||||||
async execute(invoker, command) {
|
async execute(invoker, command) {
|
||||||
|
|
||||||
const missing = invoker.channel.permissionsFor(invoker.guild.members.me).missing(command.clientPermissions);
|
const missing = invoker.channel.permissionsFor(this.client.user).missing(command.clientPermissions);
|
||||||
if (missing.length) return super._fail({ error: true, missing: missing.join(', '), silent: true });
|
if (missing.length) return super._fail({ error: true, missing: missing.join(', '), silent: true });
|
||||||
return super._succeed();
|
return super._succeed();
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ class AuditLogObserver extends Observer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async guildBanAdd({ guild, user, guildWrapper: wrapper }) {
|
async guildBanAdd({ user, guildWrapper: wrapper }) {
|
||||||
const settings = await wrapper.settings();
|
const settings = await wrapper.settings();
|
||||||
if (!settings.moderation.channel || !settings.moderation.infractions.includes('BAN')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier.
|
if (!settings.moderation.channel || !settings.moderation.infractions.includes('BAN')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier.
|
||||||
const audit = await this._fetchFirstEntry(guild, user, 'MemberBanAdd');
|
const audit = await this._fetchFirstEntry(wrapper, user, 'MemberBanAdd');
|
||||||
if (!audit) return undefined;
|
if (!audit) return undefined;
|
||||||
new Infraction(this.client, {
|
new Infraction(this.client, {
|
||||||
type: 'BAN',
|
type: 'BAN',
|
||||||
@ -37,10 +37,10 @@ class AuditLogObserver extends Observer {
|
|||||||
}).handle();
|
}).handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
async guildBanRemove({ guild, user, guildWrapper: wrapper }) {
|
async guildBanRemove({ user, guildWrapper: wrapper }) {
|
||||||
const settings = await wrapper.settings();
|
const settings = await wrapper.settings();
|
||||||
if (!settings.moderation.channel || !settings.moderation.infractions.includes('UNBAN')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier.
|
if (!settings.moderation.channel || !settings.moderation.infractions.includes('UNBAN')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier.
|
||||||
const audit = await this._fetchFirstEntry(guild, user, 'MemberBanRemove');
|
const audit = await this._fetchFirstEntry(wrapper, user, 'MemberBanRemove');
|
||||||
if (!audit) return undefined;
|
if (!audit) return undefined;
|
||||||
new Infraction(this.client, {
|
new Infraction(this.client, {
|
||||||
type: 'UNBAN',
|
type: 'UNBAN',
|
||||||
@ -56,7 +56,7 @@ class AuditLogObserver extends Observer {
|
|||||||
const { guildWrapper: wrapper } = member;
|
const { guildWrapper: wrapper } = member;
|
||||||
const settings = await wrapper.settings();
|
const settings = await wrapper.settings();
|
||||||
if (!settings.moderation.channel || !settings.moderation.infractions.includes('KICK')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier.
|
if (!settings.moderation.channel || !settings.moderation.infractions.includes('KICK')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier.
|
||||||
const audit = await this._fetchFirstEntry(member.guild, member.user, 'MemberKick');
|
const audit = await this._fetchFirstEntry(wrapper, member.user, 'MemberKick');
|
||||||
if (!audit) return undefined;
|
if (!audit) return undefined;
|
||||||
new Infraction(this.client, {
|
new Infraction(this.client, {
|
||||||
type: 'KICK',
|
type: 'KICK',
|
||||||
@ -123,7 +123,7 @@ class AuditLogObserver extends Observer {
|
|||||||
|
|
||||||
const mutedRole = settings.mute.role;
|
const mutedRole = settings.mute.role;
|
||||||
if (!mutedRole) return undefined;
|
if (!mutedRole) return undefined;
|
||||||
const audit = await this._fetchFirstEntry(newMember.guild, newMember.user, 'MemberRoleUpdate');
|
const audit = await this._fetchFirstEntry(wrapper, newMember.user, 'MemberRoleUpdate');
|
||||||
if (!audit) return undefined;
|
if (!audit) return undefined;
|
||||||
let type = null;
|
let type = null;
|
||||||
|
|
||||||
@ -148,7 +148,8 @@ class AuditLogObserver extends Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _fetchFirstEntry(guild, user, type, subtype = null) {
|
async _fetchFirstEntry(guild, user, type, subtype = null) {
|
||||||
if (!guild.members.me.permissions.has('ViewAuditLog')) return null;
|
const me = await guild.resolveMember(this.client.user);
|
||||||
|
if (!me.permissions.has('ViewAuditLog')) return null;
|
||||||
type = AuditLogEvent[type];
|
type = AuditLogEvent[type];
|
||||||
const audit = await guild.fetchAuditLogs({ limit: 1, type });
|
const audit = await guild.fetchAuditLogs({ limit: 1, type });
|
||||||
if (audit.entries.size === 0) return null;
|
if (audit.entries.size === 0) return null;
|
||||||
|
@ -133,7 +133,7 @@ module.exports = class AutoModeration extends Observer {
|
|||||||
|
|
||||||
if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
||||||
|
|
||||||
const missing = channel.permissionsFor(guild.members.me).missing('ManageMessages');
|
const missing = channel.permissionsFor(this.client.user).missing('ManageMessages');
|
||||||
if (missing.length) {
|
if (missing.length) {
|
||||||
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'word', permissions: missing });
|
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'word', permissions: missing });
|
||||||
return;
|
return;
|
||||||
@ -432,7 +432,7 @@ module.exports = class AutoModeration extends Observer {
|
|||||||
|
|
||||||
if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
||||||
|
|
||||||
const missing = channel.permissionsFor(guild.members.me).missing('ManageMessages');
|
const missing = channel.permissionsFor(this.client.user).missing('ManageMessages');
|
||||||
if (missing.length) {
|
if (missing.length) {
|
||||||
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'link', permissions: missing });
|
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'link', permissions: missing });
|
||||||
return;
|
return;
|
||||||
@ -454,9 +454,10 @@ module.exports = class AutoModeration extends Observer {
|
|||||||
let log = `${guild.name} Link filter debug:`;
|
let log = `${guild.name} Link filter debug:`;
|
||||||
|
|
||||||
for (const match of matches) {
|
for (const match of matches) {
|
||||||
const { domain } = match.match(this.regex.linkReg).groups;
|
let { domain } = match.match(this.regex.linkReg).groups;
|
||||||
|
domain = domain.toLowerCase();
|
||||||
// Invites are filtered separately
|
// Invites are filtered separately
|
||||||
if (domain.toLowerCase() === 'discord.gg') continue;
|
if (domain === 'discord.gg') continue;
|
||||||
log += `\nMatched link ${match}: `;
|
log += `\nMatched link ${match}: `;
|
||||||
|
|
||||||
const predicate = (dom) => {
|
const predicate = (dom) => {
|
||||||
@ -550,13 +551,13 @@ module.exports = class AutoModeration extends Observer {
|
|||||||
const member = message.member || await guild.members.fetch(author.id).catch(() => null);
|
const member = message.member || await guild.members.fetch(author.id).catch(() => null);
|
||||||
const settings = await wrapper.settings();
|
const settings = await wrapper.settings();
|
||||||
const { invitefilter: setting } = settings;
|
const { invitefilter: setting } = settings;
|
||||||
const { bypass, ignore, actions, silent, enabled, whitelist } = setting;
|
const { bypass, ignore, actions, silent, enabled, whitelist = [] } = setting;
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
const roles = member?.roles.cache.map((r) => r.id) || [];
|
const roles = member?.roles.cache.map((r) => r.id) || [];
|
||||||
|
|
||||||
if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
||||||
|
|
||||||
const missing = channel.permissionsFor(guild.members.me).missing('ManageMessages');
|
const missing = channel.permissionsFor(this.client.user).missing('ManageMessages');
|
||||||
if (missing.length) {
|
if (missing.length) {
|
||||||
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'invite', permissions: missing });
|
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'invite', permissions: missing });
|
||||||
return;
|
return;
|
||||||
@ -613,7 +614,7 @@ module.exports = class AutoModeration extends Observer {
|
|||||||
|
|
||||||
if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
|
||||||
|
|
||||||
const missing = channel.permissionsFor(guild.members.me).missing('ManageMessages');
|
const missing = channel.permissionsFor(this.client.user).missing('ManageMessages');
|
||||||
if (missing.length) {
|
if (missing.length) {
|
||||||
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'mention', permissions: missing });
|
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'mention', permissions: missing });
|
||||||
return;
|
return;
|
||||||
|
@ -2,6 +2,9 @@ const { EmbedBuilder, Message, ChannelType, ComponentType, ButtonStyle } = requi
|
|||||||
const { Util } = require('../../../utilities');
|
const { Util } = require('../../../utilities');
|
||||||
const { InvokerWrapper, MessageWrapper } = require('../../client/wrappers');
|
const { InvokerWrapper, MessageWrapper } = require('../../client/wrappers');
|
||||||
const { Observer, CommandError } = require('../../interfaces/');
|
const { Observer, CommandError } = require('../../interfaces/');
|
||||||
|
// const { inspect } = require('util');
|
||||||
|
|
||||||
|
const flagReg = /(?:^| )(?<flag>(?:--[a-z0-9]{3,})|(?:-[a-z]{1,2}))(?:$| )/iu;
|
||||||
|
|
||||||
class CommandHandler extends Observer {
|
class CommandHandler extends Observer {
|
||||||
|
|
||||||
@ -29,8 +32,12 @@ class CommandHandler extends Observer {
|
|||||||
|| message.author.bot
|
|| message.author.bot
|
||||||
|| message.guild && !message.guild.available) return undefined;
|
|| message.guild && !message.guild.available) return undefined;
|
||||||
|
|
||||||
|
|
||||||
const userWrapper = await this.client.getUserWrapper(message.author.id);
|
const userWrapper = await this.client.getUserWrapper(message.author.id);
|
||||||
if (!userWrapper.developer) return;
|
if (message.guild) {
|
||||||
|
const settings = await message.guildWrapper.settings();
|
||||||
|
if (!settings.textcommands.enabled && !userWrapper.developer) return;
|
||||||
|
}
|
||||||
|
|
||||||
if(message.guild) {
|
if(message.guild) {
|
||||||
if(!message.member) await message.guild.members.fetch(message.author.id);
|
if(!message.member) await message.guild.members.fetch(message.author.id);
|
||||||
@ -55,7 +62,7 @@ class CommandHandler extends Observer {
|
|||||||
// There was an error if _parseResponse return value is truthy, i.e. an error message was sent
|
// There was an error if _parseResponse return value is truthy, i.e. an error message was sent
|
||||||
if (await this._parseResponse(invoker, response)) return;
|
if (await this._parseResponse(invoker, response)) return;
|
||||||
|
|
||||||
await this._executeCommand(invoker, command.slash ? response.options.args : response.options);
|
await this._executeCommand(invoker, response.options);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +86,7 @@ class CommandHandler extends Observer {
|
|||||||
if (inhibitors.length) return this._generateError(invoker, { type: 'inhibitor', ...inhibitors[0] });
|
if (inhibitors.length) return this._generateError(invoker, { type: 'inhibitor', ...inhibitors[0] });
|
||||||
await invoker.deferReply();
|
await invoker.deferReply();
|
||||||
|
|
||||||
const response = await this._parseInteraction(interaction, command);
|
const response = await this._parseInteraction(invoker, command);
|
||||||
if (await this._parseResponse(invoker, response)) return;
|
if (await this._parseResponse(invoker, response)) return;
|
||||||
|
|
||||||
try { // Temp logging
|
try { // Temp logging
|
||||||
@ -91,8 +98,31 @@ class CommandHandler extends Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_parseResponse(invoker, response) {
|
_parseResponse(invoker, response) {
|
||||||
|
|
||||||
|
// Ensure option dependencies
|
||||||
|
outer:
|
||||||
|
if(response.options) for (const opt of Object.values(response.options)) {
|
||||||
|
let hasDep = false;
|
||||||
|
for (const dep of opt.dependsOn) {
|
||||||
|
// AND logic
|
||||||
|
if (!response.options[dep] && opt.dependsOnMode === 'AND') {
|
||||||
|
response = { option: opt, error: true, dependency: dep };
|
||||||
|
break outer;
|
||||||
|
}
|
||||||
|
// OR logic
|
||||||
|
if (response.options[dep]) hasDep = true;
|
||||||
|
}
|
||||||
|
if (!hasDep && opt.dependsOnMode === 'OR') {
|
||||||
|
response = { option: opt, error: true, dependency: opt.dependsOn.join('** OR **') };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { command } = invoker;
|
const { command } = invoker;
|
||||||
if (response.error) {
|
if (response.error && response.index) {
|
||||||
|
if(!response.emoji) response.emoji = 'failure';
|
||||||
|
return invoker.reply(response);
|
||||||
|
} else if (response.error) {
|
||||||
let content = invoker.format(`O_COMMANDHANDLER_TYPE${response.option.type}`, {
|
let content = invoker.format(`O_COMMANDHANDLER_TYPE${response.option.type}`, {
|
||||||
option: response.option.name, min: response.option.minimum, max: response.option.maximum
|
option: response.option.name, min: response.option.minimum, max: response.option.maximum
|
||||||
});
|
});
|
||||||
@ -133,9 +163,7 @@ class CommandHandler extends Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _executeCommand(invoker, options) {
|
async _executeCommand(invoker, options) {
|
||||||
// TODO defer all replies -- need to go through all commands to ensure they're not deferrign them to avoid errors
|
|
||||||
// Why? Occasionally some interacitons don't complete in time due to taking longer than normal to reach the bot -- unsure if deferring all replies will fix it
|
|
||||||
|
|
||||||
let response = null;
|
let response = null;
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
if (this.client.developmentMode && !this.client.developers.includes(invoker.user.id)) return invoker.reply({
|
if (this.client.developmentMode && !this.client.developers.includes(invoker.user.id)) return invoker.reply({
|
||||||
@ -147,7 +175,7 @@ class CommandHandler extends Observer {
|
|||||||
let debugstr = invoker.command.name;
|
let debugstr = invoker.command.name;
|
||||||
if (invoker.subcommandGroup) debugstr += ` ${invoker.subcommandGroup.name}`;
|
if (invoker.subcommandGroup) debugstr += ` ${invoker.subcommandGroup.name}`;
|
||||||
if(invoker.subcommand) debugstr += ` ${invoker.subcommand.name}`;
|
if(invoker.subcommand) debugstr += ` ${invoker.subcommand.name}`;
|
||||||
this.logger.info(`${invoker.user.tag} (${invoker.user.id}) is executing ${debugstr} in ${invoker.guild?.name || 'dms'}`);
|
this.logger.info(`[${invoker.type.toUpperCase()}] ${invoker.user.tag} (${invoker.user.id}) is executing ${debugstr} in ${invoker.guild?.name || 'dms'}`);
|
||||||
response = await invoker.command.execute(invoker, options);
|
response = await invoker.command.execute(invoker, options);
|
||||||
invoker.command.success(now);
|
invoker.command.success(now);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -174,9 +202,9 @@ class CommandHandler extends Observer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _parseInteraction(interaction, command) {
|
async _parseInteraction(invoker, command) {
|
||||||
|
|
||||||
const { subcommand } = interaction;
|
const { subcommand, guild, target: interaction } = invoker;
|
||||||
|
|
||||||
let error = null;
|
let error = null;
|
||||||
const options = {};
|
const options = {};
|
||||||
@ -193,14 +221,11 @@ class CommandHandler extends Observer {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const newOption = new CommandOption({
|
if (matched.guildOnly && !guild) return { error: true, params: { option: matched.name }, index: 'O_COMMANDHANDLER_GUILDONLY_OPT' };
|
||||||
// name: matched.name, type: matched.type,
|
const rawValue = matched.plural && typeof option.value === 'string' ? Util.parseQuotes(option.value).map(([x]) => x) : option.value;
|
||||||
// minimum: matched.minimum, maximum: matched.maximum,
|
const newOption = matched.clone(rawValue, guild, true);
|
||||||
// _rawValue: option.value,
|
const parsed = await newOption.parse();
|
||||||
// dependsOn: matched.dependsOn, dependsOnMode: matched.dependsOnMode
|
// const parsed = await this._parseOption(interaction, newOption);
|
||||||
// });
|
|
||||||
const newOption = matched.clone(option.value);
|
|
||||||
const parsed = await this._parseOption(interaction, newOption);
|
|
||||||
// console.log(parsed);
|
// console.log(parsed);
|
||||||
|
|
||||||
if(parsed.error) {
|
if(parsed.error) {
|
||||||
@ -211,7 +236,7 @@ class CommandHandler extends Observer {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
newOption.value = parsed.value;
|
// newOption.value = parsed.value;
|
||||||
options[matched.name] = newOption;
|
options[matched.name] = newOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,18 +248,6 @@ class CommandHandler extends Observer {
|
|||||||
if(!options[req.name]) return { option: req, error: true, required: true };
|
if(!options[req.name]) return { option: req, error: true, required: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure option dependencies
|
|
||||||
for (const opt of Object.values(options)) {
|
|
||||||
let hasDep = false;
|
|
||||||
for (const dep of opt.dependsOn) {
|
|
||||||
// AND logic
|
|
||||||
if (!options[dep] && opt.dependsOnMode === 'AND') return { option: opt, error: true, dependency: dep };
|
|
||||||
// OR logic
|
|
||||||
if (options[dep]) hasDep = true;
|
|
||||||
}
|
|
||||||
if(!hasDep && opt.dependsOnMode === 'OR') return { option: opt, error: true, dependency: opt.dependsOn.join('** OR **') };
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
error: false,
|
error: false,
|
||||||
options
|
options
|
||||||
@ -244,13 +257,14 @@ class CommandHandler extends Observer {
|
|||||||
|
|
||||||
async _parseMessage(invoker, params) {
|
async _parseMessage(invoker, params) {
|
||||||
|
|
||||||
const { command, target: message } = invoker;
|
const { command, target: message, guild } = invoker;
|
||||||
const { subcommands, subcommandGroups } = command;
|
const { subcommands, subcommandGroups } = command;
|
||||||
const args = {};
|
const args = {};
|
||||||
// console.log(options);
|
// console.log(options);
|
||||||
let group = null,
|
let group = null,
|
||||||
subcommand = null;
|
subcommand = null;
|
||||||
|
|
||||||
|
// Parse out subcommands
|
||||||
if (subcommandGroups.length || subcommands.length) {
|
if (subcommandGroups.length || subcommands.length) {
|
||||||
const [first, second, ...rest] = params;
|
const [first, second, ...rest] = params;
|
||||||
group = command.subcommandGroup(first);
|
group = command.subcommandGroup(first);
|
||||||
@ -258,11 +272,11 @@ class CommandHandler extends Observer {
|
|||||||
// Depending on how thoroughly I want to support old style commands this might have to try and resolve to other options
|
// Depending on how thoroughly I want to support old style commands this might have to try and resolve to other options
|
||||||
// But for now I'm followin discord's structure for commands
|
// But for now I'm followin discord's structure for commands
|
||||||
if (!group) {
|
if (!group) {
|
||||||
subcommand = command.subcommand(first)?.raw;
|
subcommand = command.subcommand(first);
|
||||||
params = [];
|
params = [];
|
||||||
if (second) params.push(second, ...rest);
|
if (second) params.push(second, ...rest);
|
||||||
} else {
|
} else {
|
||||||
subcommand = command.subcommand(second)?.raw;
|
subcommand = command.subcommand(second);
|
||||||
params = rest;
|
params = rest;
|
||||||
}
|
}
|
||||||
message.subcommand = subcommand;
|
message.subcommand = subcommand;
|
||||||
@ -275,18 +289,166 @@ class CommandHandler extends Observer {
|
|||||||
const activeCommand = subcommand || command;
|
const activeCommand = subcommand || command;
|
||||||
const flags = activeCommand.options.filter((opt) => opt.flag);
|
const flags = activeCommand.options.filter((opt) => opt.flag);
|
||||||
|
|
||||||
for (const flag of flags) {
|
params = Util.parseQuotes(params.join(' ')).map(([x]) => x);
|
||||||
|
let currentFlag = null;
|
||||||
|
// console.log('params', params);
|
||||||
|
|
||||||
|
// Parse flags
|
||||||
|
for (let index = 0; index < params.length;) {
|
||||||
|
|
||||||
|
// console.log(params[index]);
|
||||||
|
const match = flagReg.exec(params[index]);
|
||||||
|
if (!match) {
|
||||||
|
// console.log('no match', currentFlag?.name);
|
||||||
|
if (currentFlag) { // Add potential value resolveables to the flag's raw value until next flag is hit, if there is one
|
||||||
|
if (currentFlag.plural) { // The parse function only parses consecutive values
|
||||||
|
if (!currentFlag._rawValue) currentFlag._rawValue = [];
|
||||||
|
currentFlag._rawValue.push(params[index]);
|
||||||
|
} else {
|
||||||
|
currentFlag._rawValue = params[index];
|
||||||
|
currentFlag = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log('matched');
|
||||||
|
const _flag = match.groups.flag.replace(/--?/u, '').toLowerCase();
|
||||||
|
let aliased = false;
|
||||||
|
const flag = flags.find((f) => {
|
||||||
|
aliased = f.valueAsAlias && f.choices.some((c) => c.value === _flag);
|
||||||
|
return f.name === _flag || aliased;
|
||||||
|
});
|
||||||
|
if (!flag) return { error: true, index: 'O_COMMANDHANDLER_UNRECOGNISED_FLAG', params: { flag: _flag } };
|
||||||
|
else if (flag.guildOnly && !guild) return { error: true, params: { option: flag.name }, index: 'O_COMMANDHANDLER_GUILDONLY_OPT' };
|
||||||
|
|
||||||
|
// console.log('aliased', aliased);
|
||||||
|
params.splice(index, 1, null);
|
||||||
|
if (aliased) {
|
||||||
|
(args[flag.name] = flag.clone(_flag, guild))._aliased = true;
|
||||||
|
currentFlag = null;
|
||||||
|
} else {
|
||||||
|
currentFlag = flag.clone(null, guild);
|
||||||
|
args[flag.name] = currentFlag;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
// console.log('------------------------------');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up params for option parsing
|
||||||
|
for (const flag of Object.values(args)) {
|
||||||
|
// console.log('flags loop', flag.name, flag._rawValue);
|
||||||
|
const removed = await flag.parse();
|
||||||
|
if (removed.error) {
|
||||||
|
if (flag.choices.length) {
|
||||||
|
return { error: true, index: 'O_COMMANDHANDLER_INVALID_CHOICE', params: { option: flag.name, value: flag._rawValue, choices: flag.choices.map((c) => c.value).join('`, `') } };
|
||||||
|
}
|
||||||
|
return { option: flag, ...removed };
|
||||||
|
}
|
||||||
|
for(const r of removed) params.splice(params.indexOf(r), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log('params', params);
|
||||||
|
let options = activeCommand.options.filter((opt) => !opt.flag && (opt.type !== 'STRING' || opt.choices.length));
|
||||||
|
if(!guild) options = options.filter((opt) => !opt.guildOnly);
|
||||||
|
// const choiceOpts = activeCommand.options.filter((opt) => opt.choices.length);
|
||||||
|
const stringOpts = activeCommand.options.filter((opt) => !opt.flag && !opt.choices.length && opt.type === 'STRING');
|
||||||
|
// console.log('non-flag options', options.map((opt) => opt.name));
|
||||||
|
// Parse out non-flag options
|
||||||
|
for (const option of options) { // String options are parsed separately at the end
|
||||||
|
// console.log(1, params);
|
||||||
|
if (!params.some((param) => param !== null)) break;
|
||||||
|
// console.log(2);
|
||||||
|
const cloned = option.clone(null, guild);
|
||||||
|
let removed = null;
|
||||||
|
if (cloned.plural) { // E.g. if the type is CHANNEL**S**, parse out any potential channels from the message
|
||||||
|
// console.log('plural');
|
||||||
|
cloned._rawValue = params;
|
||||||
|
removed = await cloned.parse();
|
||||||
|
} else for (let index = 0; index < params.length;) { // Attempt to parse out a value from each param
|
||||||
|
// console.log('singular');
|
||||||
|
if (params[index] === null) {
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cloned._rawValue = params[index];
|
||||||
|
removed = await cloned.parse();
|
||||||
|
if (!removed.error) break;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (removed.error) continue;
|
||||||
|
|
||||||
|
args[cloned.name] = cloned;
|
||||||
|
// Clean up params for string parsing
|
||||||
|
for (const r of removed) params.splice(params.indexOf(r), 1, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { options: { args, parameters: params }, verbose: true };
|
const strings = [];
|
||||||
|
let tmpString = '';
|
||||||
|
// console.log('strings loop');
|
||||||
|
// console.log(params);
|
||||||
|
// Compile strings into groups of strings so we don't get odd looking strings from which options have been parsed out of
|
||||||
|
for (let index = 0; index < params.length;) {
|
||||||
|
const str = params[index];
|
||||||
|
// console.log(str);
|
||||||
|
if (!str) {
|
||||||
|
// console.log('null string');
|
||||||
|
if (tmpString.length) {
|
||||||
|
// console.log('pushing', tmpString);
|
||||||
|
strings.push(tmpString);
|
||||||
|
tmpString = '';
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
params.splice(index, 1);
|
||||||
|
tmpString += ` ${str}`;
|
||||||
|
tmpString = tmpString.trim();
|
||||||
|
}
|
||||||
|
// console.log('tmpString', tmpString);
|
||||||
|
if(tmpString.length) strings.push(tmpString);
|
||||||
|
|
||||||
|
// console.log('params after', params);
|
||||||
|
// console.log('strings', strings);
|
||||||
|
|
||||||
|
if (strings.length) for (const strOpt of stringOpts) {
|
||||||
|
const cloned = strOpt.clone(strings.shift());
|
||||||
|
// console.log(cloned.name, cloned._rawValue);
|
||||||
|
await cloned.parse();
|
||||||
|
args[cloned.name] = cloned;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This part is obsolete now, I think, the string option checks the choice value
|
||||||
|
for (const arg of Object.values(args)) {
|
||||||
|
// console.log(arg.name, arg.value);
|
||||||
|
if (!arg.choices.length) continue;
|
||||||
|
if (!arg.choices.some((choice) => {
|
||||||
|
if (typeof arg.value === 'string') return arg.value.toLowerCase() === choice.value.toLowerCase();
|
||||||
|
return arg.value === choice.value;
|
||||||
|
})) return { error: true, index: 'O_COMMANDHANDLER_INVALID_CHOICE', params: { option: arg.name, value: arg.value, choices: arg.choices.map((c) => c.value).join('`, `') } };
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const req of activeCommand.options.filter((opt) => opt.required))
|
||||||
|
if (!args[req.name]) return { option: req, error: true, required: true };
|
||||||
|
|
||||||
|
// console.log('parsed args final', Object.values(args).map((arg) => `\n${arg.name}: ${arg.value}, ${inspect(arg._rawValue)}`).join(''));
|
||||||
|
if (strings.length) return { error: true, index: 'O_COMMANDHANDLER_UNRECOGNISED_OPTIONS', params: { opts: strings.join('`, `') } };
|
||||||
|
|
||||||
|
return { options: args, verbose: true };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should be unnecessary -- moved to commandoption
|
||||||
async _parseOption(interaction, option) {
|
async _parseOption(interaction, option) {
|
||||||
const { guild } = interaction;
|
const { guild } = interaction;
|
||||||
|
|
||||||
const types = {
|
const types = {
|
||||||
|
POINTS: (value) => {
|
||||||
|
return { value };
|
||||||
|
},
|
||||||
ROLES: async (string) => {
|
ROLES: async (string) => {
|
||||||
const args = Util.parseQuotes(string).map(([str]) => str);
|
const args = Util.parseQuotes(string).map(([str]) => str);
|
||||||
const roles = await guild.resolveRoles(args);
|
const roles = await guild.resolveRoles(args);
|
||||||
@ -372,6 +534,7 @@ class CommandHandler extends Observer {
|
|||||||
return { error: false, value: parseInt(integer) };
|
return { error: false, value: parseInt(integer) };
|
||||||
},
|
},
|
||||||
BOOLEAN: (boolean) => {
|
BOOLEAN: (boolean) => {
|
||||||
|
boolean = this.client.resolver.resolveBoolean(boolean);
|
||||||
return { error: false, value: boolean };
|
return { error: false, value: boolean };
|
||||||
},
|
},
|
||||||
MEMBER: async (user) => {
|
MEMBER: async (user) => {
|
||||||
@ -430,7 +593,7 @@ class CommandHandler extends Observer {
|
|||||||
async _getCommand(message) {
|
async _getCommand(message) {
|
||||||
|
|
||||||
if (!this._mentionPattern) this._mentionPattern = new RegExp(`^(<@!?${this.client.user.id}>)`, 'iu');
|
if (!this._mentionPattern) this._mentionPattern = new RegExp(`^(<@!?${this.client.user.id}>)`, 'iu');
|
||||||
const [arg1, arg2, ...args] = message.content.split(' ');
|
const [arg1, arg2, ...args] = message.content.split(' ').filter((str) => str.length);
|
||||||
|
|
||||||
if (message.guild) await message.guild.settings();
|
if (message.guild) await message.guild.settings();
|
||||||
const userWrapper = await this.client.getUserWrapper(message.author.id);
|
const userWrapper = await this.client.getUserWrapper(message.author.id);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable no-labels */
|
/* eslint-disable no-labels */
|
||||||
const { WebhookClient, AttachmentBuilder } = require('discord.js');
|
const { WebhookClient, AttachmentBuilder, AuditLogEvent } = require('discord.js');
|
||||||
const { stripIndents } = require('common-tags');
|
const { stripIndents } = require('common-tags');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const { inspect } = require('util');
|
const { inspect } = require('util');
|
||||||
@ -103,22 +103,23 @@ class GuildLogger extends Observer {
|
|||||||
|
|
||||||
const hook = await guild.getWebhook('messages');
|
const hook = await guild.getWebhook('messages');
|
||||||
if (!hook) {
|
if (!hook) {
|
||||||
this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`);
|
// this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`);
|
||||||
return this.client.emit('logError', { guild, logger: 'threadLogger', reason: 'MSGLOG_NO_HOOK' });
|
return this.client.emit('logError', { guild, logger: 'threadLogger', reason: 'MSGLOG_NO_HOOK' });
|
||||||
}
|
}
|
||||||
|
|
||||||
let actor = null;
|
let actor = null;
|
||||||
const auditLogPerm = guild.members.me.permissions.has('ViewAuditLog');
|
const me = await this.client.resolver.resolveMember(this.client.user, null, guild);
|
||||||
|
const auditLogPerm = me.permissions.has('ViewAuditLog');
|
||||||
if (type === 'CREATE') actor = owner;
|
if (type === 'CREATE') actor = owner;
|
||||||
else if (type === 'DELETE' && auditLogPerm) {
|
else if (type === 'DELETE' && auditLogPerm) {
|
||||||
const auditLogs = await guild.fetchAuditLogs({ type: 'THREAD_DELETE', limit: 1 });
|
const auditLogs = await guild.fetchAuditLogs({ type: AuditLogEvent.ThreadDelete, limit: 1 });
|
||||||
const log = auditLogs.entries.first();
|
const log = auditLogs.entries.first();
|
||||||
if (log) {
|
if (log) {
|
||||||
if (thread.id !== log.target.id) return;
|
if (thread.id !== log.target.id) return;
|
||||||
actor = log.executor;
|
actor = log.executor;
|
||||||
}
|
}
|
||||||
} else if (['ARCHIVE', 'UNARCHIVE'].includes(type) && auditLogPerm) {
|
} else if (['ARCHIVE', 'UNARCHIVE'].includes(type) && auditLogPerm) {
|
||||||
const auditLogs = await guild.fetchAuditLogs({ type: 'THREAD_UPDATE', limit: 1 });
|
const auditLogs = await guild.fetchAuditLogs({ type: AuditLogEvent.ThreadUpdate, limit: 1 });
|
||||||
const log = auditLogs.entries.first();
|
const log = auditLogs.entries.first();
|
||||||
if (log) {
|
if (log) {
|
||||||
if (thread.id !== log.target.id) return;
|
if (thread.id !== log.target.id) return;
|
||||||
@ -178,7 +179,7 @@ class GuildLogger extends Observer {
|
|||||||
|
|
||||||
const hook = await wrapper.getWebhook('messages');
|
const hook = await wrapper.getWebhook('messages');
|
||||||
if (!hook) {
|
if (!hook) {
|
||||||
this.logger.debug(`Missing messageLog hook in ${wrapper.name} (${wrapper.id})`);
|
// this.logger.debug(`Missing messageLog hook in ${wrapper.name} (${wrapper.id})`);
|
||||||
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' });
|
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,13 +341,13 @@ class GuildLogger extends Observer {
|
|||||||
const { ignore, bypass } = chatlogs;
|
const { ignore, bypass } = chatlogs;
|
||||||
if (ignore.includes(channel.id)) return;
|
if (ignore.includes(channel.id)) return;
|
||||||
|
|
||||||
const missing = logChannel.permissionsFor(guild.members.me).missing(['ViewChannel', 'EmbedLinks', 'SendMessages', 'ManageWebhooks']);
|
const missing = logChannel.permissionsFor(this.client.user).missing(['ViewChannel', 'EmbedLinks', 'SendMessages', 'ManageWebhooks']);
|
||||||
if (missing.length)
|
if (missing.length)
|
||||||
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_PERMS', params: { missing: missing.join(', ') } });
|
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_PERMS', params: { missing: missing.join(', ') } });
|
||||||
|
|
||||||
const hook = await wrapper.getWebhook('messages');
|
const hook = await wrapper.getWebhook('messages');
|
||||||
if (!hook) {
|
if (!hook) {
|
||||||
this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`);
|
// this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`);
|
||||||
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' });
|
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,6 +365,7 @@ class GuildLogger extends Observer {
|
|||||||
content = Util.escapeMarkdown(content);
|
content = Util.escapeMarkdown(content);
|
||||||
|
|
||||||
if (author.bot) continue;
|
if (author.bot) continue;
|
||||||
|
// TODO: Apparently the cache for this doesn't work properly and the bot hits rate limits occasionally, make own cache at some point
|
||||||
if (!member || member.partial) member = await guild.members.fetch(message.author.id).catch(() => {
|
if (!member || member.partial) member = await guild.members.fetch(message.author.id).catch(() => {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@ -533,7 +535,7 @@ class GuildLogger extends Observer {
|
|||||||
|
|
||||||
const hook = await wrapper.getWebhook('messages');
|
const hook = await wrapper.getWebhook('messages');
|
||||||
if (!hook) {
|
if (!hook) {
|
||||||
this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`);
|
// this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`);
|
||||||
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' });
|
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -710,7 +712,7 @@ class GuildLogger extends Observer {
|
|||||||
|
|
||||||
async memberLeave(member) {
|
async memberLeave(member) {
|
||||||
|
|
||||||
const { guild, guildWrapper: wrapper } = member;
|
const { guildWrapper: wrapper } = member;
|
||||||
const settings = await wrapper.settings();
|
const settings = await wrapper.settings();
|
||||||
const setting = settings.members;
|
const setting = settings.members;
|
||||||
if (!setting.channel || !setting.enabled) return;
|
if (!setting.channel || !setting.enabled) return;
|
||||||
@ -732,7 +734,7 @@ class GuildLogger extends Observer {
|
|||||||
|
|
||||||
if (oldMember.nickname === newMember.nickname) return;
|
if (oldMember.nickname === newMember.nickname) return;
|
||||||
|
|
||||||
const { guild, user, guildWrapper: wrapper } = oldMember;
|
const { user, guildWrapper: wrapper } = oldMember;
|
||||||
const settings = await wrapper.settings();
|
const settings = await wrapper.settings();
|
||||||
const setting = settings.nicknames;
|
const setting = settings.nicknames;
|
||||||
if (!setting.channel || !setting.enabled) return;
|
if (!setting.channel || !setting.enabled) return;
|
||||||
|
31
src/structure/components/observers/Metrics.js
Normal file
31
src/structure/components/observers/Metrics.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const { Observer } = require("../../interfaces");
|
||||||
|
|
||||||
|
class Metrics extends Observer {
|
||||||
|
|
||||||
|
constructor(client) {
|
||||||
|
super(client, {
|
||||||
|
name: 'metrics',
|
||||||
|
priority: 10,
|
||||||
|
disabled: false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.hooks = [
|
||||||
|
['apiRequest', this.request.bind(this)],
|
||||||
|
['apiResponse', this.response.bind(this)]
|
||||||
|
];
|
||||||
|
|
||||||
|
this.cache = {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async request(request) {
|
||||||
|
// console.log(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
async response(request, response) {
|
||||||
|
// console.log(response, await response.json(), response.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Metrics;
|
@ -51,7 +51,8 @@ class UtilityHook extends Observer {
|
|||||||
const { guildWrapper: guild } = member;
|
const { guildWrapper: guild } = member;
|
||||||
const settings = await guild.settings();
|
const settings = await guild.settings();
|
||||||
const setting = settings.mute;
|
const setting = settings.mute;
|
||||||
if (!guild.members.me.permissions.has('ManageRoles')) return;
|
const me = await guild.resolveMember(this.client.user);
|
||||||
|
if (!me.permissions.has('ManageRoles')) return;
|
||||||
|
|
||||||
const infraction = await this.client.storageManager.mongodb.infractions.findOne({
|
const infraction = await this.client.storageManager.mongodb.infractions.findOne({
|
||||||
duration: { $gt: 0 },
|
duration: { $gt: 0 },
|
||||||
@ -79,7 +80,7 @@ class UtilityHook extends Observer {
|
|||||||
if (managed) {
|
if (managed) {
|
||||||
await member.roles.add(setting.role, 'automute upon rejoin, type 1');
|
await member.roles.add(setting.role, 'automute upon rejoin, type 1');
|
||||||
await member.roles.remove(remove, 'removing excess roles for type 1 mute');
|
await member.roles.remove(remove, 'removing excess roles for type 1 mute');
|
||||||
} else await member.roles.set(setting.role, 'automute upon join, type 1');
|
} else await member.roles.set([role], 'automute upon join, type 1');
|
||||||
|
|
||||||
} else if (infraction.data.muteType === 2) {
|
} else if (infraction.data.muteType === 2) {
|
||||||
|
|
||||||
@ -100,7 +101,8 @@ class UtilityHook extends Observer {
|
|||||||
const settings = await guild.settings();
|
const settings = await guild.settings();
|
||||||
const setting = settings.stickyrole;
|
const setting = settings.stickyrole;
|
||||||
if (!setting.roles.length || guild.premium < 1) return;
|
if (!setting.roles.length || guild.premium < 1) return;
|
||||||
if (!guild.members.me.permissions.has('ManageRoles')) return;
|
const me = await guild.resolveMember(this.client.user);
|
||||||
|
if (!me.permissions.has('ManageRoles')) return;
|
||||||
|
|
||||||
const data = await this.client.storageManager.mongodb.role_cache.findOne({ guild: guild.id, member: member.id });
|
const data = await this.client.storageManager.mongodb.role_cache.findOne({ guild: guild.id, member: member.id });
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
@ -115,7 +117,8 @@ class UtilityHook extends Observer {
|
|||||||
const settings = await guild.settings();
|
const settings = await guild.settings();
|
||||||
const setting = settings.autorole;
|
const setting = settings.autorole;
|
||||||
if (!setting.enabled) return;
|
if (!setting.enabled) return;
|
||||||
if (!guild.members.me.permissions.has('ManageRoles')) return;
|
const me = await guild.resolveMember(this.client.user);
|
||||||
|
if (!me.permissions.has('ManageRoles')) return;
|
||||||
|
|
||||||
const _roles = await guild.resolveRoles(setting.roles);
|
const _roles = await guild.resolveRoles(setting.roles);
|
||||||
const roles = _roles.map((r) => r.id);
|
const roles = _roles.map((r) => r.id);
|
||||||
@ -153,7 +156,8 @@ class UtilityHook extends Observer {
|
|||||||
|
|
||||||
const { guild } = invite;
|
const { guild } = invite;
|
||||||
if (!guild) return;
|
if (!guild) return;
|
||||||
if (!guild.members.me.permissions.has('ManageGuild')) return;
|
const me = await this.client.resolver.resolveMember(this.client.user, null, guild);
|
||||||
|
if (!me.permissions.has('ManageGuild')) return;
|
||||||
if (!guild.invites) guild.invites = await guild.fetchInvites();
|
if (!guild.invites) guild.invites = await guild.fetchInvites();
|
||||||
guild.invites.set(invite.code, invite);
|
guild.invites.set(invite.code, invite);
|
||||||
|
|
||||||
@ -163,7 +167,8 @@ class UtilityHook extends Observer {
|
|||||||
|
|
||||||
const { guild } = invite;
|
const { guild } = invite;
|
||||||
if (!guild) return;
|
if (!guild) return;
|
||||||
if (!guild.members.me.permissions.has('ManageGuild')) return;
|
const me = await this.client.resolver.resolveMember(this.client.user, null, guild);
|
||||||
|
if (!me.permissions.has('ManageGuild')) return;
|
||||||
if (!guild.invites) guild.invites = await guild.fetchInvites();
|
if (!guild.invites) guild.invites = await guild.fetchInvites();
|
||||||
guild.invites.delete(invite.code);
|
guild.invites.delete(invite.code);
|
||||||
|
|
||||||
@ -203,7 +208,8 @@ class UtilityHook extends Observer {
|
|||||||
!selfrole.channel || selfrole.channel !== channel.id ||
|
!selfrole.channel || selfrole.channel !== channel.id ||
|
||||||
!selfrole.roles.length) return;
|
!selfrole.roles.length) return;
|
||||||
|
|
||||||
const missing = guild.members.me.permissions.missing(['ManageRoles']);
|
const me = await guild.resolveMember(this.client.user);
|
||||||
|
const missing = me.permissions.missing(['ManageRoles']);
|
||||||
if (missing.length)
|
if (missing.length)
|
||||||
return this.client.emit('utilityError', { guild, utility: 'selfrole', reason: 'UTILITY_SELFROLE_PERMS', params: { missing: missing.join(', ') } });
|
return this.client.emit('utilityError', { guild, utility: 'selfrole', reason: 'UTILITY_SELFROLE_PERMS', params: { missing: missing.join(', ') } });
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
class IgnoreSetting extends Setting {
|
class IgnoreSetting extends Setting {
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ class IgnoreSetting extends Setting {
|
|||||||
bypass: { ARRAY: 'GUILD_ROLE' }
|
bypass: { ARRAY: 'GUILD_ROLE' }
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'list',
|
name: 'list',
|
||||||
description: 'List to act on',
|
description: 'List to act on',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -27,9 +27,9 @@ class IgnoreSetting extends Setting {
|
|||||||
{ name: 'channels', value: 'channels' },
|
{ name: 'channels', value: 'channels' },
|
||||||
{ name: 'bypass', value: 'bypass' }
|
{ name: 'bypass', value: 'bypass' }
|
||||||
],
|
],
|
||||||
dependsOn: ['method']
|
dependsOn: ['method']//, valueAsAlias: true, flag: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'method',
|
name: 'method',
|
||||||
description: 'Method of modifying',
|
description: 'Method of modifying',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -39,8 +39,8 @@ class IgnoreSetting extends Setting {
|
|||||||
{ name: 'set', value: 'set' },
|
{ name: 'set', value: 'set' },
|
||||||
{ name: 'reset', value: 'reset' },
|
{ name: 'reset', value: 'reset' },
|
||||||
],
|
],
|
||||||
dependsOn: ['list']
|
dependsOn: ['list']//, valueAsAlias: true, flag: true
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require('../../../interfaces/');
|
const { Setting } = require('../../../interfaces/');
|
||||||
|
|
||||||
class PermissionType extends Setting {
|
class PermissionType extends Setting {
|
||||||
|
|
||||||
@ -16,15 +16,16 @@ class PermissionType extends Setting {
|
|||||||
type: 'STRING'
|
type: 'STRING'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'type',
|
name: 'type',
|
||||||
|
description: 'Where to read permissions from',
|
||||||
choices: [
|
choices: [
|
||||||
{ name: 'discord', value: 'discord' },
|
{ name: 'discord', value: 'discord' },
|
||||||
{ name: 'both', value: 'both' },
|
{ name: 'both', value: 'both' },
|
||||||
{ name: 'grant', value: 'grant' }
|
{ name: 'grant', value: 'grant' }
|
||||||
]
|
]
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
class ProtectionSetting extends Setting {
|
class ProtectionSetting extends Setting {
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ class ProtectionSetting extends Setting {
|
|||||||
enabled: 'BOOLEAN'
|
enabled: 'BOOLEAN'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'type',
|
name: 'type',
|
||||||
description: 'Select protection type',
|
description: 'Select protection type',
|
||||||
@ -30,8 +30,8 @@ class ProtectionSetting extends Setting {
|
|||||||
{ name: 'position', value: 'position' }
|
{ name: 'position', value: 'position' }
|
||||||
],
|
],
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'roles',
|
name: 'roles',
|
||||||
description: 'Method of modifying',
|
description: 'Method of modifying',
|
||||||
@ -42,12 +42,12 @@ class ProtectionSetting extends Setting {
|
|||||||
{ name: 'reset', value: 'reset' },
|
{ name: 'reset', value: 'reset' },
|
||||||
],
|
],
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Whether setting is active or not'
|
description: 'Whether setting is active or not'
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
|
|
||||||
class SilentSetting extends Setting {
|
class SilentSetting extends Setting {
|
||||||
@ -17,11 +17,11 @@ class SilentSetting extends Setting {
|
|||||||
enabled: 'BOOLEAN'
|
enabled: 'BOOLEAN'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle state'
|
description: 'Toggle state'
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
|
class TextCommands extends Setting {
|
||||||
|
|
||||||
|
constructor(client) {
|
||||||
|
super(client, {
|
||||||
|
name: 'textcommands',
|
||||||
|
display: 'Text Commands',
|
||||||
|
description: 'Message based commands configuration',
|
||||||
|
module: 'administration',
|
||||||
|
default: {
|
||||||
|
enabled: false,
|
||||||
|
prefix: '-'
|
||||||
|
},
|
||||||
|
commandOptions: [
|
||||||
|
{
|
||||||
|
name: 'enabled',
|
||||||
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
|
description: 'Toggle enable state'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'prefix',
|
||||||
|
type: 'STRING',
|
||||||
|
description: 'Prefix to use'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(invoker, { enabled, prefix }, setting) {
|
||||||
|
|
||||||
|
if (enabled) setting.enabled = enabled.value;
|
||||||
|
if (prefix) setting.prefix = prefix.value;
|
||||||
|
return { index: 'SETTING_SUCCESS_ALT' };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fields(guild) {
|
||||||
|
const setting = guild._settings[this.name];
|
||||||
|
return [{
|
||||||
|
name: 'GENERAL_STATUS',
|
||||||
|
value: guild.format('GENERAL_STATE', {
|
||||||
|
bool: setting.enabled
|
||||||
|
}, { code: true }),
|
||||||
|
inline: true
|
||||||
|
}, {
|
||||||
|
name: 'GENERAL_PREFIX',
|
||||||
|
value: setting.prefix,
|
||||||
|
inline: true
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TextCommands;
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
const Infractions = [
|
const Infractions = [
|
||||||
'NOTE',
|
'NOTE',
|
||||||
'WARN',
|
'WARN',
|
||||||
@ -57,13 +57,13 @@ class DmInfraction extends Setting {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'message',
|
name: 'message',
|
||||||
description: 'Set the message for an infraction type',
|
description: 'Set the message for an infraction type',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
dependsOn: ['infraction']
|
dependsOn: ['infraction']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'infraction',
|
name: 'infraction',
|
||||||
description: 'Choose the infraction for which to modify the message',
|
description: 'Choose the infraction for which to modify the message',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -71,8 +71,8 @@ class DmInfraction extends Setting {
|
|||||||
return { name: inf, value: inf };
|
return { name: inf, value: inf };
|
||||||
}),
|
}),
|
||||||
dependsOn: ['message']
|
dependsOn: ['message']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'infractions',
|
name: 'infractions',
|
||||||
description: 'Modify the list of infractions that are sent',
|
description: 'Modify the list of infractions that are sent',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -82,15 +82,15 @@ class DmInfraction extends Setting {
|
|||||||
{ name: 'set', value: 'set' },
|
{ name: 'set', value: 'set' },
|
||||||
{ name: 'reset', value: 'reset' },
|
{ name: 'reset', value: 'reset' },
|
||||||
]
|
]
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Enable or disable the sending of infractions in DMs',
|
description: 'Enable or disable the sending of infractions in DMs',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
{
|
{
|
||||||
name: 'anonymous',
|
name: 'anonymous',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
description: 'Whether who issued the infraction is shown in moderation logs'
|
description: 'Whether who issued the infraction is shown in moderation logs'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
class MessageLog extends Setting {
|
class MessageLog extends Setting {
|
||||||
|
|
||||||
@ -22,16 +22,16 @@ class MessageLog extends Setting {
|
|||||||
types: { ARRAY: 'ERROR_TYPES' } // TODO: Error types
|
types: { ARRAY: 'ERROR_TYPES' } // TODO: Error types
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'channel',
|
name: 'channel',
|
||||||
description: 'Channel in which to output logs',
|
description: 'Channel in which to output logs',
|
||||||
type: 'TEXT_CHANNEL'
|
type: 'TEXT_CHANNEL'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle logging on or off',
|
description: 'Toggle logging on or off',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -39,14 +39,12 @@ class MessageLog extends Setting {
|
|||||||
|
|
||||||
async execute(interaction, opts, setting) {
|
async execute(interaction, opts, setting) {
|
||||||
|
|
||||||
const { guild } = interaction;
|
|
||||||
|
|
||||||
if (opts.enabled?.value === false) setting.channel = null;
|
if (opts.enabled?.value === false) setting.channel = null;
|
||||||
|
|
||||||
if (opts.channel) {
|
if (opts.channel) {
|
||||||
|
|
||||||
const channel = opts.channel.value;
|
const channel = opts.channel.value;
|
||||||
const perms = channel.permissionsFor(guild.members.me);
|
const perms = channel.permissionsFor(this.client.user);
|
||||||
const missingPerms = perms.missing(['ViewChannel', 'EmbedLinks', 'SendMessages']);
|
const missingPerms = perms.missing(['ViewChannel', 'EmbedLinks', 'SendMessages']);
|
||||||
if (missingPerms.length) return {
|
if (missingPerms.length) return {
|
||||||
error: true,
|
error: true,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
class MemberLog extends Setting {
|
class MemberLog extends Setting {
|
||||||
|
|
||||||
@ -21,26 +21,26 @@ class MemberLog extends Setting {
|
|||||||
leave: 'STRING'
|
leave: 'STRING'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Enable/disable member logs',
|
description: 'Enable/disable member logs',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'channel',
|
name: 'channel',
|
||||||
description: 'Select the log output channel',
|
description: 'Select the log output channel',
|
||||||
type: 'TEXT_CHANNEL'
|
type: 'TEXT_CHANNEL'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'join',
|
name: 'join',
|
||||||
description: 'Set the join message',
|
description: 'Set the join message',
|
||||||
type: 'STRING'
|
type: 'STRING', flag: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'leave',
|
name: 'leave',
|
||||||
description: 'Set the leave message',
|
description: 'Set the leave message',
|
||||||
type: 'STRING'
|
type: 'STRING', flag: true
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
const { Util } = require('../../../../utilities');
|
const { Util } = require('../../../../utilities');
|
||||||
|
|
||||||
class MessageLog extends Setting {
|
class MessageLog extends Setting {
|
||||||
@ -26,22 +26,22 @@ class MessageLog extends Setting {
|
|||||||
attachments: 'BOOLEAN'
|
attachments: 'BOOLEAN'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'channel',
|
name: 'channel',
|
||||||
description: 'Channel in which to output logs',
|
description: 'Channel in which to output logs',
|
||||||
type: 'TEXT_CHANNEL'
|
type: 'TEXT_CHANNEL'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle logging on or off',
|
description: 'Toggle logging on or off',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'attachments',
|
name: 'attachments',
|
||||||
description: 'Whether to log attachments. PREMIUM TIER 1',
|
description: 'Whether to log attachments. PREMIUM TIER 1',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'list',
|
name: 'list',
|
||||||
description: 'Select which list to modify',
|
description: 'Select which list to modify',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -50,8 +50,8 @@ class MessageLog extends Setting {
|
|||||||
{ name: 'ignore', value: 'ignore' },
|
{ name: 'ignore', value: 'ignore' },
|
||||||
],
|
],
|
||||||
dependsOn: ['method']
|
dependsOn: ['method']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'method',
|
name: 'method',
|
||||||
description: 'Select which modification method to use',
|
description: 'Select which modification method to use',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -62,7 +62,7 @@ class MessageLog extends Setting {
|
|||||||
{ name: 'reset', value: 'reset' },
|
{ name: 'reset', value: 'reset' },
|
||||||
],
|
],
|
||||||
dependsOn: ['list']
|
dependsOn: ['list']
|
||||||
}),
|
},
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ class MessageLog extends Setting {
|
|||||||
if (opts.channel) {
|
if (opts.channel) {
|
||||||
|
|
||||||
const channel = opts.channel.value;
|
const channel = opts.channel.value;
|
||||||
const perms = channel.permissionsFor(guild.members.me);
|
const perms = channel.permissionsFor(this.client.user);
|
||||||
const missingPerms = perms.missing(['ViewChannel', 'EmbedLinks', 'SendMessages', 'ManageWebhooks']);
|
const missingPerms = perms.missing(['ViewChannel', 'EmbedLinks', 'SendMessages', 'ManageWebhooks']);
|
||||||
if (missingPerms.length) return {
|
if (missingPerms.length) return {
|
||||||
error: true,
|
error: true,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const { Infractions } = require("../../../../constants/Constants");
|
const { Infractions } = require("../../../../constants/Constants");
|
||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
// [
|
// [
|
||||||
// 'NOTE',
|
// 'NOTE',
|
||||||
@ -44,17 +44,17 @@ class ModerationLog extends Setting {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Enable/disable member logs',
|
description: 'Enable/disable member logs',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'channel',
|
name: 'channel',
|
||||||
description: 'Logging channel',
|
description: 'Logging channel',
|
||||||
type: 'TEXT_CHANNEL'
|
type: 'TEXT_CHANNEL'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'infractions',
|
name: 'infractions',
|
||||||
description: 'Modify the list of infractions that are sent',
|
description: 'Modify the list of infractions that are sent',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -64,10 +64,10 @@ class ModerationLog extends Setting {
|
|||||||
{ name: 'set', value: 'set' },
|
{ name: 'set', value: 'set' },
|
||||||
{ name: 'reset', value: 'reset' },
|
{ name: 'reset', value: 'reset' },
|
||||||
]
|
]
|
||||||
}),
|
},
|
||||||
{
|
{
|
||||||
name: 'anonymous',
|
name: 'anonymous',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
description: 'Whether who issued the infraction is shown in moderation logs'
|
description: 'Whether who issued the infraction is shown in moderation logs'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
class Nicknames extends Setting {
|
class Nicknames extends Setting {
|
||||||
|
|
||||||
@ -16,16 +16,16 @@ class Nicknames extends Setting {
|
|||||||
channel: 'GUILD_TEXT'
|
channel: 'GUILD_TEXT'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle logging on or off',
|
description: 'Toggle logging on or off',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'channel',
|
name: 'channel',
|
||||||
type: 'TEXT_CHANNEL',
|
type: 'TEXT_CHANNEL',
|
||||||
description: 'Set the channel for nickname logging'
|
description: 'Set the channel for nickname logging'
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
class Voice extends Setting {
|
class Voice extends Setting {
|
||||||
|
|
||||||
@ -15,16 +15,16 @@ class Voice extends Setting {
|
|||||||
channel: 'GUILD_TEXT'
|
channel: 'GUILD_TEXT'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle logging on or off',
|
description: 'Toggle logging on or off',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'channel',
|
name: 'channel',
|
||||||
type: 'TEXT_CHANNEL',
|
type: 'TEXT_CHANNEL',
|
||||||
description: 'Set the channel for voice join/leave logging'
|
description: 'Set the channel for voice join/leave logging'
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
const Infractions = [
|
const Infractions = [
|
||||||
'WARN',
|
'WARN',
|
||||||
'MUTE',
|
'MUTE',
|
||||||
@ -17,7 +17,7 @@ class Automod extends Setting {
|
|||||||
super(client, {
|
super(client, {
|
||||||
name: 'automod',
|
name: 'automod',
|
||||||
description: 'Define automatic infraction escalation',
|
description: 'Define automatic infraction escalation',
|
||||||
display: 'Automatic Moderation',
|
display: 'Automod',
|
||||||
module: 'moderation',
|
module: 'moderation',
|
||||||
default: {
|
default: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
@ -36,17 +36,17 @@ class Automod extends Setting {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle state',
|
description: 'Toggle state',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'useprevious',
|
name: 'useprevious',
|
||||||
description: 'Use the previously passed threshold if the point total lands between two thresholds',
|
description: 'Use the previously passed threshold if the point total lands between two thresholds',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'threshold',
|
name: 'threshold',
|
||||||
description: 'The threshold at which to issue an infraction',
|
description: 'The threshold at which to issue an infraction',
|
||||||
type: 'INTEGER',
|
type: 'INTEGER',
|
||||||
@ -54,8 +54,8 @@ class Automod extends Setting {
|
|||||||
maximum: 100,
|
maximum: 100,
|
||||||
dependsOn: ['infraction', 'length'],
|
dependsOn: ['infraction', 'length'],
|
||||||
dependsOnMode: 'OR'
|
dependsOnMode: 'OR'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'infraction',
|
name: 'infraction',
|
||||||
description: 'The type of infraction to issue',
|
description: 'The type of infraction to issue',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -63,13 +63,13 @@ class Automod extends Setting {
|
|||||||
return { name: inf, value: inf };
|
return { name: inf, value: inf };
|
||||||
}),
|
}),
|
||||||
dependsOn: ['threshold']
|
dependsOn: ['threshold']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'length',
|
name: 'length',
|
||||||
description: 'The duration for a tempban or a mute',
|
description: 'The duration for a tempban or a mute',
|
||||||
type: 'TIME',
|
type: 'TIME',
|
||||||
dependsOn: ['threshold']
|
dependsOn: ['threshold']
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
|
|
||||||
class Grantable extends Setting {
|
class Grantable extends Setting {
|
||||||
@ -18,12 +18,12 @@ class Grantable extends Setting {
|
|||||||
enabled: 'BOOLEAN'
|
enabled: 'BOOLEAN'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle state'
|
description: 'Toggle state'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'roles',
|
name: 'roles',
|
||||||
description: '',
|
description: '',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -33,7 +33,7 @@ class Grantable extends Setting {
|
|||||||
{ name: 'set', value: 'set' },
|
{ name: 'set', value: 'set' },
|
||||||
{ name: 'reset', value: 'reset' },
|
{ name: 'reset', value: 'reset' },
|
||||||
]
|
]
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { FilterSetting, CommandOption } = require('../../../interfaces/');
|
const { FilterSetting } = require('../../../interfaces/');
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
|
|
||||||
class InviteFilterSetting extends FilterSetting {
|
class InviteFilterSetting extends FilterSetting {
|
||||||
@ -36,7 +36,7 @@ class InviteFilterSetting extends FilterSetting {
|
|||||||
actions: { ARRAY: 'ACTION' }
|
actions: { ARRAY: 'ACTION' }
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'method',
|
name: 'method',
|
||||||
description: 'Select which modification method to use',
|
description: 'Select which modification method to use',
|
||||||
@ -49,8 +49,8 @@ class InviteFilterSetting extends FilterSetting {
|
|||||||
{ name: 'list', value: 'list' }
|
{ name: 'list', value: 'list' }
|
||||||
],
|
],
|
||||||
dependsOn: ['list']
|
dependsOn: ['list']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'list',
|
name: 'list',
|
||||||
description: 'Select which list to modify',
|
description: 'Select which list to modify',
|
||||||
@ -61,17 +61,17 @@ class InviteFilterSetting extends FilterSetting {
|
|||||||
{ name: 'actions', value: 'actions' },
|
{ name: 'actions', value: 'actions' },
|
||||||
],
|
],
|
||||||
dependsOn: ['method']
|
dependsOn: ['method']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle enable state'
|
description: 'Toggle enable state'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'silent',
|
name: 'silent',
|
||||||
description: 'Toggle silent operation'
|
description: 'Toggle silent operation'
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { FilterSetting, CommandOption } = require('../../../interfaces/');
|
const { FilterSetting } = require('../../../interfaces/');
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
const { FilterPresets } = require('../../../../constants');
|
const { FilterPresets } = require('../../../../constants');
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class LinkFilterSetting extends FilterSetting {
|
|||||||
actions: { ARRAY: 'ACTION' }
|
actions: { ARRAY: 'ACTION' }
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'method',
|
name: 'method',
|
||||||
description: 'Select which modification method to use',
|
description: 'Select which modification method to use',
|
||||||
@ -56,8 +56,8 @@ class LinkFilterSetting extends FilterSetting {
|
|||||||
{ name: 'list', value: 'list' }
|
{ name: 'list', value: 'list' }
|
||||||
],
|
],
|
||||||
dependsOn: ['list']
|
dependsOn: ['list']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'list',
|
name: 'list',
|
||||||
description: 'Select which list to modify',
|
description: 'Select which list to modify',
|
||||||
@ -71,22 +71,22 @@ class LinkFilterSetting extends FilterSetting {
|
|||||||
{ name: 'presets', value: 'presets' }
|
{ name: 'presets', value: 'presets' }
|
||||||
],
|
],
|
||||||
dependsOn: ['method']
|
dependsOn: ['method']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle enable state'
|
description: 'Toggle enable state'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'whitelist',
|
name: 'whitelist',
|
||||||
description: 'Toggle whitelist mode'
|
description: 'Toggle whitelist mode'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'silent',
|
name: 'silent',
|
||||||
description: 'Toggle silent operation'
|
description: 'Toggle silent operation'
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { FilterSetting, CommandOption } = require('../../../interfaces/');
|
const { FilterSetting } = require('../../../interfaces/');
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
|
|
||||||
class MentionFilter extends FilterSetting {
|
class MentionFilter extends FilterSetting {
|
||||||
@ -28,27 +28,27 @@ class MentionFilter extends FilterSetting {
|
|||||||
ignore: { ARRAY: 'GUILD_TEXT' }
|
ignore: { ARRAY: 'GUILD_TEXT' }
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle state',
|
description: 'Toggle state',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'silent',
|
name: 'silent',
|
||||||
description: 'Whether the bot will respond in chat',
|
description: 'Whether the bot will respond in chat',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'unique',
|
name: 'unique',
|
||||||
description: 'Mentions for the same user count as one',
|
description: 'Mentions for the same user count as one',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'limit',
|
name: 'limit',
|
||||||
description: 'How many mentions are allowed in a message',
|
description: 'How many mentions are allowed in a message',
|
||||||
type: 'INTEGER'
|
type: 'INTEGER'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'method',
|
name: 'method',
|
||||||
description: 'Select which modification method to use',
|
description: 'Select which modification method to use',
|
||||||
@ -61,8 +61,8 @@ class MentionFilter extends FilterSetting {
|
|||||||
{ name: 'list', value: 'list' }
|
{ name: 'list', value: 'list' }
|
||||||
],
|
],
|
||||||
dependsOn: ['list']
|
dependsOn: ['list']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'list',
|
name: 'list',
|
||||||
description: 'Select which list to modify',
|
description: 'Select which list to modify',
|
||||||
@ -72,7 +72,7 @@ class MentionFilter extends FilterSetting {
|
|||||||
{ name: 'actions', value: 'actions' },
|
{ name: 'actions', value: 'actions' },
|
||||||
],
|
],
|
||||||
dependsOn: ['method']
|
dependsOn: ['method']
|
||||||
}),
|
},
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
|
|
||||||
const INFRACTIONS = ['WARN', 'MUTE', 'KICK', 'SOFTBAN', 'BAN', 'VCMUTE', 'VCKICK', 'VCBAN'];
|
const INFRACTIONS = ['WARN', 'MUTE', 'KICK', 'SOFTBAN', 'BAN', 'VCMUTE', 'VCKICK', 'VCBAN'];
|
||||||
@ -37,22 +37,22 @@ class ModerationPoints extends Setting {
|
|||||||
multiplier: false
|
multiplier: false
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
name: 'points',
|
name: 'points',
|
||||||
description: 'Point value',
|
description: 'Point value',
|
||||||
type: 'INTEGER',
|
type: 'INTEGER',
|
||||||
dependsOn: ['associate', 'type'],
|
dependsOn: ['associate', 'infraction'],
|
||||||
dependsOnMode: 'OR',
|
dependsOnMode: 'OR',
|
||||||
minimum: 0,
|
minimum: 0,
|
||||||
maximum: 100
|
maximum: 100
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'expire',
|
name: 'expire',
|
||||||
description: 'How long the points are counted for',
|
description: 'How long the points are counted for',
|
||||||
type: 'TIME',
|
type: 'TIME',
|
||||||
dependsOn: ['type']
|
dependsOn: ['infraction']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'infraction',
|
name: 'infraction',
|
||||||
description: 'Type of infraction',
|
description: 'Type of infraction',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -61,36 +61,36 @@ class ModerationPoints extends Setting {
|
|||||||
}),
|
}),
|
||||||
dependsOn: ['points', 'expire'],
|
dependsOn: ['points', 'expire'],
|
||||||
dependsOnMode: 'OR'
|
dependsOnMode: 'OR'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle on or off',
|
description: 'Toggle on or off',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'multiplier',
|
name: 'multiplier',
|
||||||
description: 'Use points as a multiplier for the expiration',
|
description: 'Use points as a multiplier for the expiration',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
name: 'associate',
|
name: 'associate',
|
||||||
description: 'Associate a word within a reason to a point value',
|
description: 'Associate a word within a reason to a point value',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
dependsOn: ['points']
|
dependsOn: ['points'], flag: true
|
||||||
}),
|
},
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(interaction, opts, setting) {
|
async execute(interaction, opts, setting) {
|
||||||
|
|
||||||
const { points, type, enabled, associate, expire, multiplier } = opts;
|
const { points, infraction, enabled, associate, expire, multiplier } = opts;
|
||||||
|
|
||||||
if (multiplier) setting.multiplier = multiplier.value;
|
if (multiplier) setting.multiplier = multiplier.value;
|
||||||
if (enabled) setting.enabled = enabled.value;
|
if (enabled) setting.enabled = enabled.value;
|
||||||
if (expire) setting.expirations[type.value] = expire.value * 1000;
|
if (expire) setting.expirations[infraction.value] = expire.value * 1000;
|
||||||
if (associate) setting.associations[associate.value.toLowerCase()] = points.value;
|
if (associate) setting.associations[associate.value.toLowerCase()] = points.value;
|
||||||
if (type && points) setting.points[type.value] = points.value;
|
if (infraction && points) setting.points[infraction.value] = points.value;
|
||||||
|
|
||||||
return { index: 'SETTING_SUCCESS_ALT' };
|
return { index: 'SETTING_SUCCESS_ALT' };
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require('../../../interfaces/');
|
const { Setting } = require('../../../interfaces/');
|
||||||
const { inspect } = require('util');
|
const { inspect } = require('util');
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
|
|
||||||
@ -52,28 +52,28 @@ class MuteSetting extends Setting {
|
|||||||
permanent: 'BOOLEAN'
|
permanent: 'BOOLEAN'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING', flag: true,
|
||||||
name: 'create',
|
name: 'create',
|
||||||
description: 'Create a mute role, mutually exclusive with role'
|
description: 'Create a mute role, mutually exclusive with role'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'ROLE',
|
type: 'ROLE',
|
||||||
name: 'role',
|
name: 'role',
|
||||||
description: 'Select the role to use for mutes, mutually exclusive with create'
|
description: 'Select the role to use for mutes, mutually exclusive with create'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'TIME',
|
type: 'TIME', flag: true,
|
||||||
name: 'default',
|
name: 'default',
|
||||||
description: 'Set the default duration for mutes'
|
description: 'Set the default duration for mutes'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'permanent',
|
name: 'permanent',
|
||||||
description: 'Whether to allow permanent mutes or fall back to default mute duration'
|
description: 'Whether to allow permanent mutes or fall back to default mute duration'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'INTEGER',
|
type: 'INTEGER', flag: true,
|
||||||
name: 'type',
|
name: 'type',
|
||||||
description: 'Select the type of mute behaviour',
|
description: 'Select the type of mute behaviour',
|
||||||
choices: [ {
|
choices: [ {
|
||||||
@ -89,7 +89,7 @@ class MuteSetting extends Setting {
|
|||||||
name: 'Type 3 (Use Discord timeouts)',
|
name: 'Type 3 (Use Discord timeouts)',
|
||||||
value: 3
|
value: 3
|
||||||
} ]
|
} ]
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -187,7 +187,8 @@ class MuteSetting extends Setting {
|
|||||||
return role;
|
return role;
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasPermission = guild.members.me.permissions.has('ManageRoles');
|
const me = await guild.resolveMember(this.client.user);
|
||||||
|
const hasPermission = me.permissions.has('ManageRoles');
|
||||||
if (!hasPermission) return {
|
if (!hasPermission) return {
|
||||||
index: 'SETTING_MUTE_ROLEMISSINGPERMISSION',
|
index: 'SETTING_MUTE_ROLEMISSINGPERMISSION',
|
||||||
error: true
|
error: true
|
||||||
@ -251,7 +252,7 @@ class MuteSetting extends Setting {
|
|||||||
|
|
||||||
for (const channel of channels.values()) {
|
for (const channel of channels.values()) {
|
||||||
|
|
||||||
if (!channel.permissionsFor(guild.members.me).has('ManageRoles')) {
|
if (!channel.permissionsFor(this.client.user).has('ManageRoles')) {
|
||||||
issues.push({ type: 'permission', channel: channel.name });
|
issues.push({ type: 'permission', channel: channel.name });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ class StaffSetting extends Setting {
|
|||||||
}, {
|
}, {
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Whether the staff command is in use',
|
description: 'Whether the staff command is in use',
|
||||||
type: 'BOOLEAN'
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
const { FilterSetting, CommandOption } = require('../../../interfaces/');
|
const { FilterSetting } = require('../../../interfaces/');
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
const { FilterPresets } = require('../../../../constants');
|
const { FilterPresets } = require('../../../../constants');
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ class WordFilterSetting extends FilterSetting {
|
|||||||
actions: { ARRAY: 'ACTION' }
|
actions: { ARRAY: 'ACTION' }
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'method',
|
name: 'method',
|
||||||
description: 'Select which modification method to use',
|
description: 'Select which modification method to use',
|
||||||
@ -57,8 +57,8 @@ class WordFilterSetting extends FilterSetting {
|
|||||||
{ name: 'list', value: 'list' }
|
{ name: 'list', value: 'list' }
|
||||||
],
|
],
|
||||||
dependsOn: ['list']
|
dependsOn: ['list']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'list',
|
name: 'list',
|
||||||
description: 'Select which list to modify',
|
description: 'Select which list to modify',
|
||||||
@ -73,17 +73,17 @@ class WordFilterSetting extends FilterSetting {
|
|||||||
{ name: 'actions', value: 'actions' },
|
{ name: 'actions', value: 'actions' },
|
||||||
],
|
],
|
||||||
dependsOn: ['method']
|
dependsOn: ['method']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle enable state'
|
description: 'Toggle enable state'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'silent',
|
name: 'silent',
|
||||||
description: 'Toggle silent operation'
|
description: 'Toggle silent operation'
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { FilterSetting, CommandOption } = require('../../../interfaces/');
|
const { FilterSetting } = require('../../../interfaces/');
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
|
|
||||||
class WordWatcher extends FilterSetting {
|
class WordWatcher extends FilterSetting {
|
||||||
@ -10,6 +10,7 @@ class WordWatcher extends FilterSetting {
|
|||||||
description: 'Flag messages for potentially offensive content instead of deleting automatically',
|
description: 'Flag messages for potentially offensive content instead of deleting automatically',
|
||||||
module: 'moderation',
|
module: 'moderation',
|
||||||
default: {
|
default: {
|
||||||
|
enabled: false,
|
||||||
channel: null,
|
channel: null,
|
||||||
words: [],
|
words: [],
|
||||||
regex: [],
|
regex: [],
|
||||||
@ -18,7 +19,7 @@ class WordWatcher extends FilterSetting {
|
|||||||
actions: []
|
actions: []
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'method',
|
name: 'method',
|
||||||
description: 'Select which modification method to use',
|
description: 'Select which modification method to use',
|
||||||
@ -31,8 +32,8 @@ class WordWatcher extends FilterSetting {
|
|||||||
{ name: 'list', value: 'list' }
|
{ name: 'list', value: 'list' }
|
||||||
],
|
],
|
||||||
dependsOn: ['list']
|
dependsOn: ['list']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'list',
|
name: 'list',
|
||||||
description: 'Select which list to modify',
|
description: 'Select which list to modify',
|
||||||
@ -44,12 +45,17 @@ class WordWatcher extends FilterSetting {
|
|||||||
{ name: 'actions', value: 'actions' },
|
{ name: 'actions', value: 'actions' },
|
||||||
],
|
],
|
||||||
dependsOn: ['method']
|
dependsOn: ['method']
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
|
name: 'enabled',
|
||||||
|
description: 'Toggle enable state'
|
||||||
|
},
|
||||||
|
{
|
||||||
name: 'channel',
|
name: 'channel',
|
||||||
type: 'TEXT_CHANNEL',
|
type: 'TEXT_CHANNEL',
|
||||||
description: 'Where to output flagged messages'
|
description: 'Where to output flagged messages',
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
|
|
||||||
class Autorole extends Setting {
|
class Autorole extends Setting {
|
||||||
@ -18,7 +18,7 @@ class Autorole extends Setting {
|
|||||||
enabled: 'BOOLEAN'
|
enabled: 'BOOLEAN'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'roles',
|
name: 'roles',
|
||||||
description: 'Modification method for roles',
|
description: 'Modification method for roles',
|
||||||
@ -30,12 +30,12 @@ class Autorole extends Setting {
|
|||||||
{ name: 'edit', value: 'edit' },
|
{ name: 'edit', value: 'edit' },
|
||||||
{ name: 'list', value: 'list' }
|
{ name: 'list', value: 'list' }
|
||||||
]
|
]
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle enable state'
|
description: 'Toggle enable state'
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
const { Util } = require("../../../../utilities");
|
const { Util } = require("../../../../utilities");
|
||||||
|
|
||||||
class Autorole extends Setting {
|
class Autorole extends Setting {
|
||||||
@ -18,7 +18,7 @@ class Autorole extends Setting {
|
|||||||
enabled: 'BOOLEAN'
|
enabled: 'BOOLEAN'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'roles',
|
name: 'roles',
|
||||||
description: 'Modification method for roles',
|
description: 'Modification method for roles',
|
||||||
@ -30,12 +30,12 @@ class Autorole extends Setting {
|
|||||||
{ name: 'edit', value: 'edit' },
|
{ name: 'edit', value: 'edit' },
|
||||||
{ name: 'list', value: 'list' }
|
{ name: 'list', value: 'list' }
|
||||||
]
|
]
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle enable state'
|
description: 'Toggle enable state'
|
||||||
})
|
}
|
||||||
],
|
],
|
||||||
premium: 1
|
premium: 1
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { Setting, CommandOption } = require("../../../interfaces");
|
const { Setting } = require("../../../interfaces");
|
||||||
|
|
||||||
class Autorole extends Setting {
|
class Autorole extends Setting {
|
||||||
|
|
||||||
@ -17,16 +17,16 @@ class Autorole extends Setting {
|
|||||||
enabled: 'BOOLEAN'
|
enabled: 'BOOLEAN'
|
||||||
},
|
},
|
||||||
commandOptions: [
|
commandOptions: [
|
||||||
new CommandOption({
|
{
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
name: 'message',
|
name: 'message',
|
||||||
description: 'Set the welcome message'
|
description: 'Set the welcome message'
|
||||||
}),
|
},
|
||||||
new CommandOption({
|
{
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
|
||||||
name: 'enabled',
|
name: 'enabled',
|
||||||
description: 'Toggle enable state'
|
description: 'Toggle enable state'
|
||||||
})
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,8 @@ class AddroleInfraction extends Infraction {
|
|||||||
const { grantable } = await this.guild.settings();
|
const { grantable } = await this.guild.settings();
|
||||||
|
|
||||||
let filtered = [];
|
let filtered = [];
|
||||||
const { highest: clientHighest } = this.guild.members.me.roles;
|
const me = await this.guild.resolveMember(this.client.user);
|
||||||
|
const { highest: clientHighest } = me.roles;
|
||||||
filtered = this.data.roles.filter((r) => r.comparePositionTo(clientHighest) < 0);
|
filtered = this.data.roles.filter((r) => r.comparePositionTo(clientHighest) < 0);
|
||||||
if (filtered.length === 0) {
|
if (filtered.length === 0) {
|
||||||
return super._fail('C_ADDROLE_ROLEHIERARCHYBOT');
|
return super._fail('C_ADDROLE_ROLEHIERARCHYBOT');
|
||||||
|
@ -48,7 +48,7 @@ class BanInfraction extends Infraction {
|
|||||||
const callbacks = this.client.moderationManager.callbacks.filter((c) => c.infraction.type === 'BAN'
|
const callbacks = this.client.moderationManager.callbacks.filter((c) => c.infraction.type === 'BAN'
|
||||||
&& c.infraction.target === this.target.id);
|
&& c.infraction.target === this.target.id);
|
||||||
|
|
||||||
if (callbacks.size > 0) callbacks.map((c) => this.client.moderationManager.removeCallback(c.infraction));
|
if (callbacks.size > 0) callbacks.map((c) => this.client.moderationManager.removeCallback(c.infraction, true));
|
||||||
|
|
||||||
return this._succeed();
|
return this._succeed();
|
||||||
|
|
||||||
@ -56,13 +56,14 @@ class BanInfraction extends Infraction {
|
|||||||
|
|
||||||
async verify() {
|
async verify() {
|
||||||
|
|
||||||
if (this.target instanceof GuildMember) {
|
const member = await this.guild.resolveMember(this.target.id);
|
||||||
if (!this.member.bannable) return super._fail('C_BAN_CANNOTBEBANNED');
|
if (member && !member.bannable)
|
||||||
}
|
return super._fail('C_BAN_CANNOTBEBANNED');
|
||||||
|
|
||||||
|
|
||||||
let alreadyBanned = null;
|
let alreadyBanned = null;
|
||||||
try {
|
try {
|
||||||
alreadyBanned = await this.guild.bans.fetch(this.member.id);
|
alreadyBanned = await this.guild.bans.fetch(this.target.id);
|
||||||
} catch (e) { } //eslint-disable-line no-empty
|
} catch (e) { } //eslint-disable-line no-empty
|
||||||
|
|
||||||
if (alreadyBanned) return super._fail('C_BAN_ALREADYBANNED');
|
if (alreadyBanned) return super._fail('C_BAN_ALREADYBANNED');
|
||||||
|
@ -140,9 +140,9 @@ class LockdownInfraction extends Infraction {
|
|||||||
|
|
||||||
async verify() {
|
async verify() {
|
||||||
|
|
||||||
const perms = this.target.permissionsFor(this.guild.members.me);
|
const perms = this.target.permissionsFor(this.client.user);
|
||||||
const missing = perms.missing(['ManageRoles', 'SendMessages', 'AddReactions']);
|
const missing = perms.missing(['ManageRoles', 'SendMessages', 'AddReactions']);
|
||||||
if(missing.length) return this._fail('INFRACTION_LOCKDOWN_MISSING_PERMS', { missing: missing.join('**, **') });
|
if (missing.length) return this._fail(this.guild.format('INFRACTION_LOCKDOWN_MISSING_PERMS', { missing: missing.join('**, **') }), null, true);
|
||||||
return super._verify();
|
return super._verify();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,8 @@ class MuteInfraction extends Infraction {
|
|||||||
role = await this.client.resolver.resolveRole(setting.role, true, this.guild);
|
role = await this.client.resolver.resolveRole(setting.role, true, this.guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const me = await this.guild.resolveMember(this.client.user);
|
||||||
|
|
||||||
let removed = [];
|
let removed = [];
|
||||||
switch (setting.type) {
|
switch (setting.type) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -60,12 +62,12 @@ class MuteInfraction extends Infraction {
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
removed = this.member.roles.cache.filter((r) => !r.managed &&
|
removed = this.member.roles.cache.filter((r) => !r.managed &&
|
||||||
r.comparePositionTo(this.guild.members.me.roles.highest) < 0 &&
|
r.comparePositionTo(me.roles.highest) < 0 &&
|
||||||
r.id !== this.guild.id);
|
r.id !== this.guild.id);
|
||||||
try {
|
try {
|
||||||
await this.member.roles.set([
|
await this.member.roles.set([
|
||||||
...this.member.roles.cache.filter((r) => r.managed ||
|
...this.member.roles.cache.filter((r) => r.managed ||
|
||||||
r.comparePositionTo(this.guild.members.me.roles.highest) >= 0 ||
|
r.comparePositionTo(me.roles.highest) >= 0 ||
|
||||||
r.id === this.guild.id).values(),
|
r.id === this.guild.id).values(),
|
||||||
role
|
role
|
||||||
], this._reason);
|
], this._reason);
|
||||||
@ -76,11 +78,11 @@ class MuteInfraction extends Infraction {
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
removed = this.member.roles.cache.filter((r) => !r.managed &&
|
removed = this.member.roles.cache.filter((r) => !r.managed &&
|
||||||
r.comparePositionTo(this.guild.members.me.roles.highest) < 0 &&
|
r.comparePositionTo(me.roles.highest) < 0 &&
|
||||||
r.id !== this.guild.id);
|
r.id !== this.guild.id);
|
||||||
try {
|
try {
|
||||||
await this.member.roles.set(this.member.roles.cache.filter((r) => r.managed ||
|
await this.member.roles.set(this.member.roles.cache.filter((r) => r.managed ||
|
||||||
r.comparePositionTo(this.guild.members.me.roles.highest) >= 0 ||
|
r.comparePositionTo(me.roles.highest) >= 0 ||
|
||||||
r.id === this.guild.id), this._reason);
|
r.id === this.guild.id), this._reason);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.client.logger.error(`Mute infraction failed to calculate removeable roles, might want to check this out.\n${error.stack || error}`);
|
this.client.logger.error(`Mute infraction failed to calculate removeable roles, might want to check this out.\n${error.stack || error}`);
|
||||||
@ -96,6 +98,8 @@ class MuteInfraction extends Infraction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.member.voice.channel) await this.member.voice.disconnect(this._reason);
|
||||||
|
|
||||||
this.data = {
|
this.data = {
|
||||||
removedRoles: removed.map((r) => r.id),
|
removedRoles: removed.map((r) => r.id),
|
||||||
muteType: setting.type,
|
muteType: setting.type,
|
||||||
@ -107,7 +111,7 @@ class MuteInfraction extends Infraction {
|
|||||||
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
this.data.removedRoles = [...new Set([...this.data.removedRoles, ...callback.infraction.data.removedRoles])];
|
this.data.removedRoles = [...new Set([...this.data.removedRoles, ...callback.infraction.data.removedRoles])];
|
||||||
this.client.moderationManager.removeCallback(callback.infraction);
|
this.client.moderationManager.removeCallback(callback.infraction, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if(callbacks.size > 0) callbacks.map((c) => this.client.moderationManager._removeExpiration(c));
|
// if(callbacks.size > 0) callbacks.map((c) => this.client.moderationManager._removeExpiration(c));
|
||||||
@ -134,10 +138,12 @@ class MuteInfraction extends Infraction {
|
|||||||
return this._fail('COMMAND_MUTE_INVALIDMUTEROLE', true);
|
return this._fail('COMMAND_MUTE_INVALIDMUTEROLE', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const me = await this.guild.resolveMember(this.client.user);
|
||||||
if (settings.mute.type === 3) {
|
if (settings.mute.type === 3) {
|
||||||
if (this.guild.members.me.permissions.missing('ModerateMembers').length) return this._fail('COMMAND_MUTE_MISSING_MODERATE_PERM', true);
|
if (me.permissions.missing('ModerateMembers').length) return this._fail('COMMAND_MUTE_MISSING_MODERATE_PERM', true);
|
||||||
|
if (me.roles.highest.position <= this.member.roles.highest.position) return this._fail('COMMAND_MUTE_HIERARCHY_ERROR');
|
||||||
// if (!this.duration && !settings.mute.default)
|
// if (!this.duration && !settings.mute.default)
|
||||||
} else if (this.guild.members.me.permissions.missing('ManageRoles').length) return this._fail('COMMAND_MUTE_MISSING_MANAGEROLE_PERM');
|
} else if (me.permissions.missing('ManageRoles').length) return this._fail('COMMAND_MUTE_MISSING_MANAGEROLE_PERM');
|
||||||
|
|
||||||
return super._verify();
|
return super._verify();
|
||||||
|
|
||||||
|
@ -82,7 +82,8 @@ class NicknameInfraction extends Infraction {
|
|||||||
async verify() {
|
async verify() {
|
||||||
|
|
||||||
const { highest } = this.member.roles;
|
const { highest } = this.member.roles;
|
||||||
if (highest.comparePositionTo(this.guild.members.me.roles.highest) > 0 || !this.guild.members.me.permissions.has('ManageNicknames')) {
|
const me = await this.guild.resolveMember(this.client.user);
|
||||||
|
if (highest.comparePositionTo(me.roles.highest) > 0 || !me.permissions.has('ManageNicknames')) {
|
||||||
return this._fail('C_NICKNAME_MISSINGPERMISSIONS');
|
return this._fail('C_NICKNAME_MISSINGPERMISSIONS');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,8 @@ class RemoveroleInfraction extends Infraction {
|
|||||||
const { grantable } = await this.guild.settings();
|
const { grantable } = await this.guild.settings();
|
||||||
|
|
||||||
let filtered = [];
|
let filtered = [];
|
||||||
const { highest: clientHighest } = this.guild.members.me.roles;
|
const me = await this.guild.resolveMember(this.client.user);
|
||||||
|
const { highest: clientHighest } = me.roles;
|
||||||
filtered = this.data.roles.filter((r) => r.comparePositionTo(clientHighest) < 0);
|
filtered = this.data.roles.filter((r) => r.comparePositionTo(clientHighest) < 0);
|
||||||
if (filtered.length === 0) {
|
if (filtered.length === 0) {
|
||||||
return super._fail('C_REMOVEROLE_ROLEHIERARCHYBOT');
|
return super._fail('C_REMOVEROLE_ROLEHIERARCHYBOT');
|
||||||
|
@ -39,7 +39,7 @@ class UnbanInfraction extends Infraction {
|
|||||||
const callbacks = this.client.moderationManager.callbacks.filter((c) => c.infraction.type === 'BAN'
|
const callbacks = this.client.moderationManager.callbacks.filter((c) => c.infraction.type === 'BAN'
|
||||||
&& c.infraction.target === this.target.id);
|
&& c.infraction.target === this.target.id);
|
||||||
|
|
||||||
if (callbacks.size > 0) callbacks.map((c) => this.client.moderationManager.removeCallback(c.infraction));
|
if (callbacks.size > 0) callbacks.map((c) => this.client.moderationManager.removeCallback(c.infraction, true));
|
||||||
|
|
||||||
await this.handle();
|
await this.handle();
|
||||||
return this._succeed();
|
return this._succeed();
|
||||||
|
@ -95,9 +95,9 @@ class UnlockdownInfraction extends Infraction {
|
|||||||
|
|
||||||
async verify() {
|
async verify() {
|
||||||
|
|
||||||
const perms = this.target.permissionsFor(this.guild.members.me);
|
const perms = this.target.permissionsFor(this.client.user);
|
||||||
const missing = perms.missing(['ManageRoles', 'SendMessages', 'AddReactions']);
|
const missing = perms.missing(['ManageRoles', 'SendMessages', 'AddReactions']);
|
||||||
if(missing.length) return this._fail('INFRACTION_LOCKDOWN_MISSING_PERMS', { missing: missing.join('**, **') });
|
if (missing.length) this._fail(this.guild.format('INFRACTION_LOCKDOWN_MISSING_PERMS', { missing: missing.join('**, **') }), null, true);
|
||||||
return super._verify();
|
return super._verify();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
|
|
||||||
|
const { ChannelType } = require("discord.js");
|
||||||
|
|
||||||
const Constants = {
|
const Constants = {
|
||||||
CommandOptionTypes: {
|
CommandOptionTypes: {
|
||||||
SUB_COMMAND: 1,
|
SUB_COMMAND: 1,
|
||||||
@ -28,7 +30,8 @@ const Constants = {
|
|||||||
ROLE: 8,
|
ROLE: 8,
|
||||||
MENTIONABLE: 9,
|
MENTIONABLE: 9,
|
||||||
NUMBER: 10,
|
NUMBER: 10,
|
||||||
FLOAT: 10
|
FLOAT: 10,
|
||||||
|
POINTS: 4
|
||||||
},
|
},
|
||||||
ChannelTypes: {
|
ChannelTypes: {
|
||||||
TEXT_CHANNEL: 0,
|
TEXT_CHANNEL: 0,
|
||||||
@ -36,12 +39,17 @@ const Constants = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PointsReg = /^([-+]?[0-9]+) ?(points|point|pts|pt|p)$/iu;
|
||||||
|
|
||||||
class CommandOption {
|
class CommandOption {
|
||||||
|
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
|
|
||||||
|
this._options = options;
|
||||||
this.name = options.name;
|
this.name = options.name;
|
||||||
this.description = options.description || "A missing description, let a bot developer know.";
|
this.description = options.description || "A missing description, let a bot developer know.";
|
||||||
|
if(!options.client) throw new Error(`${this.name} is missing client`);
|
||||||
|
this.client = options.client;
|
||||||
|
|
||||||
this.type = Object.keys(Constants.CommandOptionTypes).includes(options.type) ? options.type : 'STRING';
|
this.type = Object.keys(Constants.CommandOptionTypes).includes(options.type) ? options.type : 'STRING';
|
||||||
this.required = Boolean(options.required);
|
this.required = Boolean(options.required);
|
||||||
@ -52,8 +60,10 @@ class CommandOption {
|
|||||||
if (options.options)
|
if (options.options)
|
||||||
for (const opt of options.options) {
|
for (const opt of options.options) {
|
||||||
// console.log(opt);
|
// console.log(opt);
|
||||||
if (opt instanceof CommandOption) this.options.push(opt);
|
if (opt instanceof CommandOption) {
|
||||||
else if (opt.name instanceof Array) {
|
opt.client = this.client;
|
||||||
|
this.options.push(opt);
|
||||||
|
} else if (opt.name instanceof Array) {
|
||||||
const { name: names, description, type, dependsOn, ...opts } = opt;
|
const { name: names, description, type, dependsOn, ...opts } = opt;
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
// console.log(name);
|
// console.log(name);
|
||||||
@ -69,9 +79,12 @@ class CommandOption {
|
|||||||
if (dependsOn instanceof Array) {
|
if (dependsOn instanceof Array) {
|
||||||
_dependsOn = dependsOn[index];
|
_dependsOn = dependsOn[index];
|
||||||
}
|
}
|
||||||
this.options.push(new CommandOption({ name, type: _type, description: desc, dependsOn: _dependsOn, ...opts }));
|
this.options.push(new CommandOption({
|
||||||
|
client: this.client, name, type: _type,
|
||||||
|
description: desc, dependsOn: _dependsOn, ...opts
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
} else this.options.push(new CommandOption(opt));
|
} else this.options.push(new CommandOption({ client: this.client, ...opt }));
|
||||||
}
|
}
|
||||||
// this.options = options.options || []; //Used for SUB_COMMAND/SUB_COMMAND_GROUP types.
|
// this.options = options.options || []; //Used for SUB_COMMAND/SUB_COMMAND_GROUP types.
|
||||||
|
|
||||||
@ -83,32 +96,51 @@ class CommandOption {
|
|||||||
this.minimum = typeof options.minimum === 'number' ? options.minimum : undefined; //Used for INTEGER/NUMBER/FLOAT types.
|
this.minimum = typeof options.minimum === 'number' ? options.minimum : undefined; //Used for INTEGER/NUMBER/FLOAT types.
|
||||||
this.maximum = typeof options.maximum === 'number' ? options.maximum : undefined;
|
this.maximum = typeof options.maximum === 'number' ? options.maximum : undefined;
|
||||||
|
|
||||||
this.flag = true; // used with message based command options
|
this.slashOption = options.slashOption || false;
|
||||||
|
this.flag = options.flag ?? false; // used with message based command options
|
||||||
|
this.valueOptional = options.valueOptional ?? false;
|
||||||
|
this.defaultValue = options.defaultValue ?? null;
|
||||||
|
this.valueAsAlias = options.choices?.length && (options.valueAsAlias ?? false);
|
||||||
|
// this.words = options.words ?? null; // Used when parsing strings if the command has multiple string types that aren't flags
|
||||||
|
|
||||||
this.value = undefined;
|
this.value = undefined;
|
||||||
|
|
||||||
|
// Used in cloned options when parsing final value
|
||||||
|
this.guild = options.guild || null;
|
||||||
this._rawValue = options._rawValue ?? null; //Raw value input from Discord. -- use ?? where the value is potentially false, otherwise we end up with false -> null
|
this._rawValue = options._rawValue ?? null; //Raw value input from Discord. -- use ?? where the value is potentially false, otherwise we end up with false -> null
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
usage(guild) {
|
get guildOnly() {
|
||||||
const name = `》 ${this.name.toUpperCase()} [${this.type}]`;
|
return ['ROLE', 'MEMBER', 'CHANNEL'].some((t) => this.type.includes(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
usage(guild, verbose = false) {
|
||||||
|
let name = `》 ${this.name.toUpperCase()} [${this.type}]`;
|
||||||
|
let flagProps = ['flag'];
|
||||||
|
if (this.valueOptional) flagProps.push('optional value');
|
||||||
|
if (this.defaultValue !== null) flagProps.push(`default value: \`${this.defaultValue}\``);
|
||||||
|
flagProps = `(${flagProps.join(', ')})`;
|
||||||
|
if(this.flag) name += ` ${flagProps}`;
|
||||||
let value = null;
|
let value = null;
|
||||||
|
|
||||||
|
const format = (...args) => guild ? guild.format(...args) : this.client.format(...args);
|
||||||
|
|
||||||
if (this.type === 'SUB_COMMAND_GROUP') {
|
if (this.type === 'SUB_COMMAND_GROUP') {
|
||||||
value = this.options.map((opt) => {
|
value = this.options.map((opt) => {
|
||||||
const usage = opt.usage(guild);
|
const usage = opt.usage(guild, true);
|
||||||
return `__${usage.name.replace('》', '').trim()}__\n${usage.value}`;
|
return `__${usage.name.replace('》', '').trim()}__\n${usage.value}`;
|
||||||
}).join('\n\n');
|
}).join('\n\n');
|
||||||
} else if (this.type === 'SUB_COMMAND') {
|
} else if (this.type === 'SUB_COMMAND') {
|
||||||
if (!this.options.length) value = guild.format('GENERAL_NO_ARGS');
|
if (!this.options.length) value = format('GENERAL_NO_ARGS');
|
||||||
else value = this.options.map((opt) => opt.usage(guild).value).join('\n');
|
else value = this.options.map((opt) => opt.usage(guild, true).value).join('\n');
|
||||||
} else {
|
} else {
|
||||||
value = `**${this.name} [${this.type}]:** ${this.description}`;
|
value = `${verbose ? `**${this.name} [${this.type}]** ${this.flag ? flagProps : ''}\n` : ''}`;
|
||||||
|
value += `${this.description}`;
|
||||||
if (this.choices.length)
|
if (this.choices.length)
|
||||||
value += `\n__${guild.format('GENERAL_CHOICES')}__: ${this.choices.map((choice) => choice.name).join(', ')}`;
|
value += `\n__${format('GENERAL_CHOICES')}__: ${this.choices.map((choice) => choice.name).join(', ')}`;
|
||||||
if (this.dependsOn.length)
|
if (this.dependsOn.length)
|
||||||
value += `\n${guild.format('GENERAL_DEPENDSON', { dependencies: this.dependsOn.join('`, `') })}`;
|
value += `\n${format('GENERAL_DEPENDSON', { dependencies: this.dependsOn.join('`, `') })}`;
|
||||||
if (this.minimum !== undefined)
|
if (this.minimum !== undefined)
|
||||||
value += `\nMIN: \`${this.minimum}\``;
|
value += `\nMIN: \`${this.minimum}\``;
|
||||||
if (this.maximum !== undefined) {
|
if (this.maximum !== undefined) {
|
||||||
@ -130,20 +162,268 @@ class CommandOption {
|
|||||||
* @return {CommandOption}
|
* @return {CommandOption}
|
||||||
* @memberof CommandOption
|
* @memberof CommandOption
|
||||||
*/
|
*/
|
||||||
clone(value) {
|
clone(_rawValue, guild, slashOption = false) {
|
||||||
return new CommandOption({
|
return new CommandOption({
|
||||||
name: this.name, type: this.type,
|
...this._options, _rawValue, guild, slashOption
|
||||||
minimum: this.minimum, maximum: this.maximum,
|
|
||||||
dependsOn: this.dependsOn, dependsOnMode: this.dependsOnMode,
|
|
||||||
_rawValue: value, strict: this.strict
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async parse() {
|
||||||
|
if(!this._rawValue && !this.valueOptional) throw new Error(`Null _rawValue`);
|
||||||
|
// console.log('-------PARSE BEGIN---------');
|
||||||
|
// console.log('1', this.name, this._rawValue, this.valueOptional);
|
||||||
|
const { removed, value, error } = await this.types[this.type]();
|
||||||
|
// console.log('2', removed, value, error);
|
||||||
|
// console.log('--------PARSE END----------');
|
||||||
|
if(error) return { error };
|
||||||
|
this.value = value;
|
||||||
|
return removed || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
format(index, params, opts) {
|
||||||
|
if (this.guild) return this.guild.format(index, params, opts);
|
||||||
|
return this.client.format(index, params, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
get types() {
|
||||||
|
return {
|
||||||
|
POINTS: () => {
|
||||||
|
if(this.slashOption) return { value: this._rawValue };
|
||||||
|
let value = null,
|
||||||
|
removed = null;
|
||||||
|
for (const str of this._rawValue) {
|
||||||
|
const num = parseInt(str);
|
||||||
|
if (isNaN(num)) continue;
|
||||||
|
if(PointsReg.test(str)) {
|
||||||
|
value = num; removed = [str];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const index = this._rawValue.indexOf(str);
|
||||||
|
const next = this._rawValue[index + 1];
|
||||||
|
const tmp = str + next;
|
||||||
|
if (PointsReg.test(tmp)) {
|
||||||
|
value = num; removed= [str, next];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.minimum !== undefined && value < this.minimum) return { error: true };
|
||||||
|
if (this.maximum !== undefined && value > this.maximum) return { error: true };
|
||||||
|
return { value, removed };
|
||||||
|
},
|
||||||
|
ROLES: async () => {
|
||||||
|
const roles = [],
|
||||||
|
removed = [];
|
||||||
|
for (const str of this._rawValue) {
|
||||||
|
const role = await this.guild.resolveRole(str, this.strict);
|
||||||
|
if (role) {
|
||||||
|
roles.push(role);
|
||||||
|
removed.push(str);
|
||||||
|
} else if(roles.length) break;
|
||||||
|
}
|
||||||
|
if (!roles.length) return { error: true };
|
||||||
|
return { value: roles, removed };
|
||||||
|
},
|
||||||
|
MEMBERS: async () => {
|
||||||
|
const members = [],
|
||||||
|
removed = [];
|
||||||
|
for (const arg of this._rawValue) {
|
||||||
|
const member = await this.guild.resolveMember(arg, this.strict);
|
||||||
|
if (member) {
|
||||||
|
members.push(member);
|
||||||
|
removed.push(arg);
|
||||||
|
} else if(members.length) break;
|
||||||
|
}
|
||||||
|
if (!members.length) return { error: true, message: this.strict ? this.format('O_COMMANDHANDLER_TYPEMEMBER_STRICT') : null };
|
||||||
|
return { value: members, removed };
|
||||||
|
},
|
||||||
|
USERS: async () => {
|
||||||
|
const users = [],
|
||||||
|
removed = [];
|
||||||
|
for (const arg of this._rawValue) {
|
||||||
|
const user = await this.client.resolveUser(arg, this.strict);
|
||||||
|
if (user) {
|
||||||
|
users.push(user);
|
||||||
|
removed.push(arg);
|
||||||
|
} else if(users.length) break;
|
||||||
|
}
|
||||||
|
if (!users.length) return { error: true, message: this.strict ? this.format('O_COMMANDHANDLER_TYPEUSERS_STRICT') : null };
|
||||||
|
return { value: users, removed };
|
||||||
|
},
|
||||||
|
CHANNELS: async () => {
|
||||||
|
const channels = [],
|
||||||
|
removed = [];
|
||||||
|
for (const arg of this._rawValue) {
|
||||||
|
const channel = await this.guild.resolveChannel(arg, this.strict);
|
||||||
|
if (channel) {
|
||||||
|
channels.push(channel);
|
||||||
|
removed.push(arg);
|
||||||
|
} else if(channels.length) break;
|
||||||
|
}
|
||||||
|
if (!channels.length) return { error: true };
|
||||||
|
return { value: channels, removed };
|
||||||
|
},
|
||||||
|
TEXT_CHANNELS: async () => {
|
||||||
|
const channels = [],
|
||||||
|
removed = [];
|
||||||
|
for(const arg of this._rawValue) {
|
||||||
|
const channel = await this.guild.resolveChannel(arg, this.strict, (channel) => channel.type === ChannelType.GuildText);
|
||||||
|
if (channel) {
|
||||||
|
channels.push(channel);
|
||||||
|
removed.push(arg);
|
||||||
|
} else if(channels.length) break;
|
||||||
|
}
|
||||||
|
if (!channels.length) return { error: true };
|
||||||
|
return { value: channels, removed };
|
||||||
|
},
|
||||||
|
VOICE_CHANNELS: async () => {
|
||||||
|
const channels = [],
|
||||||
|
removed = [];
|
||||||
|
for (const arg of this._rawValue) {
|
||||||
|
const channel = await this.guild.resolveChannel(arg, this.strict, (channel) => channel.type === ChannelType.GuildVoice);
|
||||||
|
if (channel) {
|
||||||
|
channels.push(channel);
|
||||||
|
removed.push(arg);
|
||||||
|
} else if(channels.length) break;
|
||||||
|
}
|
||||||
|
if (!channels.length) return { error: true };
|
||||||
|
return { value: channels, removed };
|
||||||
|
},
|
||||||
|
TIME: () => {
|
||||||
|
const value = this.client.resolver.resolveTime(this._rawValue);
|
||||||
|
if (value === null) return { error: true };
|
||||||
|
return { value, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
COMPONENT: () => {
|
||||||
|
const [component] = this.client.resolver.components(this._rawValue, 'any');
|
||||||
|
if (!component) return { error: true };
|
||||||
|
return { value: component, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
COMPONENTS: () => {
|
||||||
|
const strings = this._rawValue;
|
||||||
|
const components = [],
|
||||||
|
removed = [];
|
||||||
|
for (const str of strings) {
|
||||||
|
const [component] = this.client.resolver.components(str, 'any');
|
||||||
|
if (component && !components.includes(component)) {
|
||||||
|
components.push(component);
|
||||||
|
removed.push(str);
|
||||||
|
} else if(components.length) break;
|
||||||
|
}
|
||||||
|
if (!components.length) return { error: true };
|
||||||
|
return { value: components, removed };
|
||||||
|
},
|
||||||
|
COMMAND: () => {
|
||||||
|
const [command] = this.client.resolver.components(this._rawValue, 'command');
|
||||||
|
if (!command) return { error: true };
|
||||||
|
return { value: command, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
COMMANDS: () => {
|
||||||
|
const strings = this._rawValue;
|
||||||
|
const commands = [],
|
||||||
|
removed = [];
|
||||||
|
for (const str of strings) {
|
||||||
|
const [command] = this.client.resolver.components(str, 'command');
|
||||||
|
if (command && !commands.includes(command)) {
|
||||||
|
commands.push(command);
|
||||||
|
removed.push(str);
|
||||||
|
} else if(commands.length) break;
|
||||||
|
}
|
||||||
|
if (!commands.length) return { error: true };
|
||||||
|
return { value: commands, removed };
|
||||||
|
},
|
||||||
|
MODULE: () => {
|
||||||
|
const [module] = this.client.resolver.components(this._rawValue, 'module');
|
||||||
|
if (!module) return { error: true };
|
||||||
|
return { value: module, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
STRING: () => {
|
||||||
|
if (this.slashOption) return { value: this._rawValue };
|
||||||
|
if (this._aliased) return { value: this._rawValue, removed: [] };
|
||||||
|
if (this.choices.length) {
|
||||||
|
const found = this.choices.find((c) => c.value.toLowerCase() === this._rawValue.toLowerCase());
|
||||||
|
if (found) return { value: found.value, removed: [this._rawValue] };
|
||||||
|
return { error: true };
|
||||||
|
}
|
||||||
|
return { value: this._rawValue, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
INTEGER: () => {
|
||||||
|
const integer = parseInt(this._rawValue);
|
||||||
|
if(isNaN(integer)) return { error: true };
|
||||||
|
if (this.minimum !== undefined && integer < this.minimum) return { error: true };
|
||||||
|
if (this.maximum !== undefined && integer > this.maximum) return { error: true };
|
||||||
|
return { value: integer, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
BOOLEAN: () => {
|
||||||
|
const boolean = this.client.resolver.resolveBoolean(this._rawValue);
|
||||||
|
if (boolean === null && this.valueOptional) return { value: this.defaultValue, removed: [] };
|
||||||
|
else if(boolean === null) return { error: true };
|
||||||
|
return { value: boolean, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
MEMBER: async () => {
|
||||||
|
const member = await this.guild.resolveMember(this._rawValue, this.strict);
|
||||||
|
if (!member) return { error: true };
|
||||||
|
return { value: member, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
USER: async () => {
|
||||||
|
const user = await this.client.resolver.resolveUser(this._rawValue, this.strict);
|
||||||
|
if(!user) return { error: true };
|
||||||
|
return { value: user, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
TEXT_CHANNEL: async () => {
|
||||||
|
const channel = await this.guild.resolveChannel(this._rawValue);
|
||||||
|
if (!channel || channel.type !== ChannelType.GuildText) return { error: true };
|
||||||
|
return { value: channel, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
VOICE_CHANNEL: async () => {
|
||||||
|
const channel = await this.guild.resolveChannel(this._rawValue);
|
||||||
|
if (!channel || channel.type !== ChannelType.GuildVoice) return { error: true };
|
||||||
|
return { value: channel, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
CHANNEL: async () => {
|
||||||
|
const channel = await this.guild.resolveChannel(this._rawValue);
|
||||||
|
if(!channel) return { error: true };
|
||||||
|
return { value: channel, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
ROLE: async () => {
|
||||||
|
const role = await this.guild.resolveRole(this._rawValue);
|
||||||
|
if(!role) return { error: true };
|
||||||
|
return { value: role, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
MENTIONABLE: (mentionable) => {
|
||||||
|
return { value: mentionable };
|
||||||
|
},
|
||||||
|
NUMBER: () => {
|
||||||
|
const number = parseFloat(this._rawValue);
|
||||||
|
if(isNaN(number))return { error: true };
|
||||||
|
if (this.minimum !== undefined && number < this.minimum) return { error: true };
|
||||||
|
if (this.maximum !== undefined && number > this.maximum) return { error: true };
|
||||||
|
return { value: number, removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
FLOAT: () => {
|
||||||
|
const float = parseFloat(this._rawValue);
|
||||||
|
if(isNaN(float)) return { error: true };
|
||||||
|
if (this.minimum !== undefined && float < this.minimum) return { error: true };
|
||||||
|
if (this.maximum !== undefined && float > this.maximum) return { error: true };
|
||||||
|
return { value: parseFloat(float), removed: [this._rawValue] };
|
||||||
|
},
|
||||||
|
DATE: async () => {
|
||||||
|
const date = await this.client.resolver.resolveDate(this._rawValue);
|
||||||
|
if (!date) return { error: true };
|
||||||
|
return { value: date, removed: [this._rawValue] };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get plural() {
|
||||||
|
return this.type.endsWith('S');
|
||||||
|
}
|
||||||
|
|
||||||
get raw() {
|
get raw() {
|
||||||
return {
|
return {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
type: this.type,
|
type: this.type,
|
||||||
options: []
|
options: this.options.map((opt) => opt.raw)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ const {
|
|||||||
} = require('../../constants');
|
} = require('../../constants');
|
||||||
|
|
||||||
const { Util } = require('../../utilities');
|
const { Util } = require('../../utilities');
|
||||||
|
const { inspect } = require('util');
|
||||||
|
|
||||||
const Constants = {
|
const Constants = {
|
||||||
MaxCharacters: 1024, // Max embed description is 2048 characters, however some of those description characters are going to usernames, types, filler text, etc.
|
MaxCharacters: 1024, // Max embed description is 2048 characters, however some of those description characters are going to usernames, types, filler text, etc.
|
||||||
@ -147,7 +148,7 @@ class Infraction {
|
|||||||
if(this._mongoId) filter._id = this._mongoId;
|
if(this._mongoId) filter._id = this._mongoId;
|
||||||
return this.client.storageManager.mongodb.infractions.updateOne(filter, this.json)
|
return this.client.storageManager.mongodb.infractions.updateOne(filter, this.json)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.client.logger.error(`There was an issue saving infraction data to the database.\n${error.stack || error}\nInfraction data:\n${this.json}`);
|
this.client.logger.error(`There was an issue saving infraction data to the database.\n${error.stack || error}\nInfraction data:\n${inspect(this.json)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,9 +326,10 @@ class Infraction {
|
|||||||
if (protection.type === 'position') {
|
if (protection.type === 'position') {
|
||||||
const executorHighest = executor.roles.highest;
|
const executorHighest = executor.roles.highest;
|
||||||
const targetHighest = target.roles.highest;
|
const targetHighest = target.roles.highest;
|
||||||
if (executorHighest.comparePositionTo(targetHighest) < 0) {
|
if (executorHighest.comparePositionTo(targetHighest) === 0)
|
||||||
|
return this._fail('INFRACTION_PROTECTIONPOSITIONERROR_SAME');
|
||||||
|
if (executorHighest.comparePositionTo(targetHighest) < 0)
|
||||||
return this._fail('INFRACTION_PROTECTIONPOSITIONERROR');
|
return this._fail('INFRACTION_PROTECTIONPOSITIONERROR');
|
||||||
}
|
|
||||||
} else if (protection.type === 'role') {
|
} else if (protection.type === 'role') {
|
||||||
const contains = target.roles.cache.some((r) => protection.roles.includes(r.id));
|
const contains = target.roles.cache.some((r) => protection.roles.includes(r.id));
|
||||||
if (contains) {
|
if (contains) {
|
||||||
|
@ -7,7 +7,6 @@ const Component = require("./Component.js");
|
|||||||
// Imports to enable JSDocs typing
|
// Imports to enable JSDocs typing
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
const InteractionWrapper = require("../client/wrappers/InteractionWrapper.js");
|
const InteractionWrapper = require("../client/wrappers/InteractionWrapper.js");
|
||||||
const CommandOption = require('./CommandOption.js');
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
// const { DiscordClient } = require("../DiscordClient.js");
|
// const { DiscordClient } = require("../DiscordClient.js");
|
||||||
|
|
||||||
@ -70,29 +69,9 @@ class Setting extends Component {
|
|||||||
this.default = { [this.name]: options.default || {} };
|
this.default = { [this.name]: options.default || {} };
|
||||||
this.definitions = options.definitions || {}; // Used for the API for field definitions
|
this.definitions = options.definitions || {}; // Used for the API for field definitions
|
||||||
|
|
||||||
this.commandOptions = [];
|
this.commandOptions = options.commandOptions || [];
|
||||||
this.commandType = options.commandType || 'SUB_COMMAND';
|
this.commandType = options.commandType || 'SUB_COMMAND';
|
||||||
|
|
||||||
if (options.commandOptions)
|
|
||||||
for (const opt of options.commandOptions) {
|
|
||||||
if (opt instanceof CommandOption) this.commandOptions.push(opt);
|
|
||||||
else if (opt.name instanceof Array) {
|
|
||||||
const { name: names, description, type, ...opts } = opt;
|
|
||||||
for (const name of names) {
|
|
||||||
// console.log(name);
|
|
||||||
const index = names.indexOf(name);
|
|
||||||
let desc = description,
|
|
||||||
_type = type;
|
|
||||||
if (description instanceof Array) desc = description[index] || 'Missing description';
|
|
||||||
if (type instanceof Array) {
|
|
||||||
_type = type[index];
|
|
||||||
if (!_type) throw new Error(`Missing type for option ${name} in command ${this.name}`);
|
|
||||||
}
|
|
||||||
this.commandOptions.push(new CommandOption({ name, type: _type, description: desc, ...opts }));
|
|
||||||
}
|
|
||||||
} else this.commandOptions.push(new CommandOption(opt));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.clientPermissions = options.clientPermissions || [];
|
this.clientPermissions = options.clientPermissions || [];
|
||||||
this.memberPermissions = options.memberPermissions || []; // Idk if we'll end up using this but it's here anyway
|
this.memberPermissions = options.memberPermissions || []; // Idk if we'll end up using this but it's here anyway
|
||||||
|
|
||||||
@ -125,22 +104,23 @@ class Setting extends Component {
|
|||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
name: `》 ${guild.format(`GENERAL_OPTIONS`)}`,
|
name: `》 ${guild.format(`GENERAL_OPTIONS`)}`,
|
||||||
value: options.map(
|
value: options.map((opt) => opt.usage(guild, true)).map((f) => f.value).join('\n\n')
|
||||||
(opt) => {
|
// value: options.map(
|
||||||
let msg = `**${opt.name} [${opt.type}]:** ${opt.description}`;
|
// (opt) => {
|
||||||
if (opt.choices.length)
|
// let msg = `**${opt.name} [${opt.type}]:** ${opt.description}`;
|
||||||
msg += `\n__${guild.format('GENERAL_CHOICES')}__: ${opt.choices.map((choice) => choice.name).join(', ')}`;
|
// if (opt.choices.length)
|
||||||
if (opt.dependsOn.length)
|
// msg += `\n__${guild.format('GENERAL_CHOICES')}__: ${opt.choices.map((choice) => choice.name).join(', ')}`;
|
||||||
msg += `\n${guild.format('GENERAL_DEPENDSON', { dependencies: opt.dependsOn.join('`, `') })}`;
|
// if (opt.dependsOn.length)
|
||||||
if (opt.minimum !== undefined)
|
// msg += `\n${guild.format('GENERAL_DEPENDSON', { dependencies: opt.dependsOn.join('`, `') })}`;
|
||||||
msg += `\nMIN: \`${opt.minimum}\``;
|
// if (opt.minimum !== undefined)
|
||||||
if (opt.maximum !== undefined) {
|
// msg += `\nMIN: \`${opt.minimum}\``;
|
||||||
const newline = opt.minimum !== undefined ? ', ' : '\n';
|
// if (opt.maximum !== undefined) {
|
||||||
msg += `${newline}MAX: \`${opt.maximum}\``;
|
// const newline = opt.minimum !== undefined ? ', ' : '\n';
|
||||||
}
|
// msg += `${newline}MAX: \`${opt.maximum}\``;
|
||||||
return msg;
|
// }
|
||||||
}
|
// return msg;
|
||||||
).join('\n\n')
|
// }
|
||||||
|
// ).join('\n\n')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,16 +183,16 @@ class Setting extends Component {
|
|||||||
if (!message.length && !index && !embed) 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 invoker.promptMessage(
|
const response = await invoker.promptMessage(
|
||||||
index ? invoker.format(index, params) : message,
|
index ? invoker.format(index, params) : message,
|
||||||
{ time, editReply: true, embed }
|
{ time, editReply: invoker.replied, embed }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response) return { error: true, message: invoker.format('ERR_TIMEOUT') };
|
if (!response) return { error: true, message: invoker.format('ERR_TIMEOUT') };
|
||||||
const content = response.content.toLowerCase();
|
const content = response.content.toLowerCase();
|
||||||
if(invoker.channel.permissionsFor(invoker.guild.members.me).has('ManageMessages'))
|
if (invoker.channel.permissionsFor(this.client.user).has('ManageMessages'))
|
||||||
await response.delete().catch(() => null);
|
await response.delete().catch(() => null);
|
||||||
if (['cancel', 'abort', 'exit'].includes(content)) return {
|
if (['cancel', 'abort', 'exit'].includes(content)) return {
|
||||||
error: true,
|
error: true,
|
||||||
message: invoker.format('ERR_CANCEL')
|
content: invoker.format('ERR_CANCEL')
|
||||||
};
|
};
|
||||||
else if (!content.length) return { error: true, index: 'SETTING_NOCONTENT' };
|
else if (!content.length) return { error: true, index: 'SETTING_NOCONTENT' };
|
||||||
|
|
||||||
@ -241,7 +221,8 @@ class Setting extends Component {
|
|||||||
|
|
||||||
for (const param of params) {
|
for (const param of params) {
|
||||||
if (list.includes(param)) {
|
if (list.includes(param)) {
|
||||||
list.splice(list.indexOf(!caseSensitive ? param : param.toLowerCase()), 1);
|
const [removed] = list.splice(list.indexOf(!caseSensitive ? param : param.toLowerCase()), 1);
|
||||||
|
modified.push(removed);
|
||||||
} else skipped.push(param);
|
} else skipped.push(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +51,10 @@ class Command extends Component {
|
|||||||
|
|
||||||
this.options = [];
|
this.options = [];
|
||||||
if (options.options) for (const opt of options.options) {
|
if (options.options) for (const opt of options.options) {
|
||||||
if (opt instanceof CommandOption) this.options.push(opt);
|
if (opt instanceof CommandOption) {
|
||||||
else if (opt.name instanceof Array) {
|
opt.client = client;
|
||||||
|
this.options.push(opt);
|
||||||
|
} else if (opt.name instanceof Array) {
|
||||||
// Allows easy templating of subcommands that share arguments
|
// Allows easy templating of subcommands that share arguments
|
||||||
const { name: names, description, type, ...opts } = opt;
|
const { name: names, description, type, ...opts } = opt;
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
@ -64,9 +66,9 @@ class Command extends Component {
|
|||||||
_type = type[index];
|
_type = type[index];
|
||||||
if (!_type) throw new Error(`Missing type for option ${name} in command ${this.name}`);
|
if (!_type) throw new Error(`Missing type for option ${name} in command ${this.name}`);
|
||||||
}
|
}
|
||||||
this.options.push(new CommandOption({ name, type: _type, description: desc, ...opts }));
|
this.options.push(new CommandOption({ name, type: _type, description: desc, ...opts, client }));
|
||||||
}
|
}
|
||||||
} else this.options.push(new CommandOption(opt));
|
} else this.options.push(new CommandOption({ ...opt, client }));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.options.sort((a, b) => {
|
this.options.sort((a, b) => {
|
||||||
@ -107,7 +109,11 @@ class Command extends Component {
|
|||||||
|
|
||||||
const fields = [];
|
const fields = [];
|
||||||
const { guild, subcommand, subcommandGroup } = invoker;
|
const { guild, subcommand, subcommandGroup } = invoker;
|
||||||
const { permissions: { type } } = guild._settings;
|
|
||||||
|
let type = null;
|
||||||
|
const format = (index) => guild ? guild.format(index) : this.client.format(index);
|
||||||
|
if (guild) ({ permissions: { type } } = guild._settings);
|
||||||
|
|
||||||
|
|
||||||
if (this.options.length) {
|
if (this.options.length) {
|
||||||
if (verbose) fields.push(...this.options.map((opt) => opt.usage(guild)));
|
if (verbose) fields.push(...this.options.map((opt) => opt.usage(guild)));
|
||||||
@ -126,7 +132,7 @@ class Command extends Component {
|
|||||||
else if (type === 'grant') required = [this.resolveable];
|
else if (type === 'grant') required = [this.resolveable];
|
||||||
else required = [this.resolveable, ...this.memberPermissions];
|
else required = [this.resolveable, ...this.memberPermissions];
|
||||||
fields.push({
|
fields.push({
|
||||||
name: `》 ${guild.format('GENERAL_PERMISSIONS')}`,
|
name: `》 ${format('GENERAL_PERMISSIONS')}`,
|
||||||
value: `\`${required.join('`, `')}\``
|
value: `\`${required.join('`, `')}\``
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -135,7 +141,7 @@ class Command extends Component {
|
|||||||
author: {
|
author: {
|
||||||
name: `${this.name} [module:${this.module.name}]`
|
name: `${this.name} [module:${this.module.name}]`
|
||||||
},
|
},
|
||||||
description: guild.format(`COMMAND_${this.name.toUpperCase()}_HELP`),
|
description: format(`COMMAND_${this.name.toUpperCase()}_HELP`),
|
||||||
fields
|
fields
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ class ModerationCommand extends SlashCommand {
|
|||||||
|
|
||||||
constructor(client, opts) {
|
constructor(client, opts) {
|
||||||
|
|
||||||
|
const flag = true;
|
||||||
let baseOptions = [
|
let baseOptions = [
|
||||||
{
|
{
|
||||||
name: 'users',
|
name: 'users',
|
||||||
@ -13,28 +14,32 @@ class ModerationCommand extends SlashCommand {
|
|||||||
strict: true
|
strict: true
|
||||||
}, {
|
}, {
|
||||||
name: 'points',
|
name: 'points',
|
||||||
type: 'INTEGER',
|
type: 'POINTS',
|
||||||
description: 'The amount of points to assign to the infraction',
|
description: 'The amount of points to assign to the infraction',
|
||||||
minimum: 0,
|
minimum: 0,
|
||||||
maximum: 100
|
maximum: 100
|
||||||
}, {
|
}, {
|
||||||
name: 'expiration',
|
name: 'expiration',
|
||||||
type: 'TIME',
|
type: 'TIME',
|
||||||
description: 'How long until the points expire'
|
description: 'How long until the points expire',
|
||||||
|
flag
|
||||||
}, {
|
}, {
|
||||||
name: 'prune',
|
name: 'prune',
|
||||||
type: 'INTEGER',
|
type: 'INTEGER',
|
||||||
description: 'How many messages to prune',
|
description: 'How many messages to prune',
|
||||||
minimum: 2,
|
minimum: 2,
|
||||||
maximum: 100
|
maximum: 100,
|
||||||
|
flag
|
||||||
}, {
|
}, {
|
||||||
name: 'force',
|
name: 'force',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
description: 'Whether to override automod'
|
description: 'Whether to override automod',
|
||||||
|
flag, valueOptional: true, defaultValue: true
|
||||||
}, {
|
}, {
|
||||||
name: 'silent',
|
name: 'silent',
|
||||||
type: 'BOOLEAN',
|
type: 'BOOLEAN',
|
||||||
description: 'Whether the user should receive the infraction'
|
description: 'Whether the user should receive the infraction',
|
||||||
|
flag, valueOptional: true, defaultValue: true
|
||||||
}, {
|
}, {
|
||||||
name: 'reason',
|
name: 'reason',
|
||||||
type: 'STRING',
|
type: 'STRING',
|
||||||
@ -42,7 +47,6 @@ class ModerationCommand extends SlashCommand {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// Probably temporary
|
|
||||||
if(!opts.memberPermissions) throw new Error(`MISSING PERMS ${opts.name}`);
|
if(!opts.memberPermissions) throw new Error(`MISSING PERMS ${opts.name}`);
|
||||||
|
|
||||||
if (opts.skipOptions) for (const opt of opts.skipOptions) {
|
if (opts.skipOptions) for (const opt of opts.skipOptions) {
|
||||||
|
@ -10,26 +10,16 @@ class SettingsCommand extends SlashCommand {
|
|||||||
super(client, {
|
super(client, {
|
||||||
...options,
|
...options,
|
||||||
guildOnly: true,
|
guildOnly: true,
|
||||||
memberPermissions: ['ManageGuild']
|
memberPermissions: ['ManageGuild'],
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
name: 'settings',
|
|
||||||
description: "Configure the bot's behaviour in your server",
|
|
||||||
module: 'administration',
|
|
||||||
options: [
|
options: [
|
||||||
|
{
|
||||||
],
|
type: 'SUB_COMMAND',
|
||||||
guildOnly: true
|
name: 'list',
|
||||||
}
|
description: 'List available settings'
|
||||||
*/
|
}
|
||||||
|
]
|
||||||
this.options.push(new CommandOption({
|
});
|
||||||
type: 'SUB_COMMAND',
|
|
||||||
name: 'list',
|
|
||||||
description: 'List available settings'
|
|
||||||
}));
|
|
||||||
this.build();
|
this.build();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -50,9 +40,12 @@ class SettingsCommand extends SlashCommand {
|
|||||||
name: setting.name,
|
name: setting.name,
|
||||||
description: setting.description,
|
description: setting.description,
|
||||||
type: setting.commandType, //'SUB_COMMAND',
|
type: setting.commandType, //'SUB_COMMAND',
|
||||||
options: setting.commandOptions
|
options: setting.commandOptions,
|
||||||
|
client: this.client
|
||||||
});
|
});
|
||||||
this.options.push(subCommand);
|
this.options.push(subCommand);
|
||||||
|
// Overwrite the setting options with the built CommandOption structures
|
||||||
|
setting.commandOptions = subCommand.options;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (const module of modules) {
|
// for (const module of modules) {
|
||||||
@ -89,7 +82,8 @@ class SettingsCommand extends SlashCommand {
|
|||||||
if (!setting) return invoker.reply('Something went wrong, could not find setting');
|
if (!setting) return invoker.reply('Something went wrong, could not find setting');
|
||||||
|
|
||||||
if (setting.clientPermissions.length) {
|
if (setting.clientPermissions.length) {
|
||||||
const missing = guild.members.me.permissions.missing(setting.clientPermissions);
|
const me = await guild.resolveMember(this.client.user);
|
||||||
|
const missing = me.permissions.missing(setting.clientPermissions);
|
||||||
if (missing.length) return invoker.reply({
|
if (missing.length) return invoker.reply({
|
||||||
emoji: 'failure',
|
emoji: 'failure',
|
||||||
index: 'SETTING_MISSING_CLIENTPERMISSIONS',
|
index: 'SETTING_MISSING_CLIENTPERMISSIONS',
|
||||||
|
@ -197,6 +197,8 @@ module.exports = class FilterUtility {
|
|||||||
//Zero width character (UTF-16 8206)
|
//Zero width character (UTF-16 8206)
|
||||||
content = content.replace(//gu, '');
|
content = content.replace(//gu, '');
|
||||||
|
|
||||||
|
content = content.replace(/['"‘’“”]/gu, '');
|
||||||
|
|
||||||
//Replace the weird letters with their normal text counterparts
|
//Replace the weird letters with their normal text counterparts
|
||||||
// eslint-disable-next-line no-useless-escape
|
// eslint-disable-next-line no-useless-escape
|
||||||
const match = (/[a-z0-9\w\(\)\.\\\/\?!]+/gimu).exec(content);
|
const match = (/[a-z0-9\w\(\)\.\\\/\?!]+/gimu).exec(content);
|
||||||
@ -321,7 +323,9 @@ module.exports = class FilterUtility {
|
|||||||
matched: true,
|
matched: true,
|
||||||
_matcher: _word,
|
_matcher: _word,
|
||||||
matcher: `fuzzy [\`${_word}\`, \`${sim}\`, \`${threshold}\`]`,
|
matcher: `fuzzy [\`${_word}\`, \`${sim}\`, \`${threshold}\`]`,
|
||||||
type: 'fuzzy'
|
type: 'fuzzy',
|
||||||
|
_threshold: threshold,
|
||||||
|
_sim: sim
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ class SettingsMigrator {
|
|||||||
stickyrole: result.stickyrole ? { ...result.stickyrole, enabled: Boolean(result.stickyrole.roles.length) } : undefined,
|
stickyrole: result.stickyrole ? { ...result.stickyrole, enabled: Boolean(result.stickyrole.roles.length) } : undefined,
|
||||||
welcomer: result.welcomer,
|
welcomer: result.welcomer,
|
||||||
commands: { disabled: result.disabledCommands, custom: {} },
|
commands: { disabled: result.disabledCommands, custom: {} },
|
||||||
prefix: result.prefix
|
textcommands: { prefix: result.prefix, enabled: false }
|
||||||
};
|
};
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
@ -287,14 +287,15 @@ class SettingsMigrator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (linkfilter) settings.linkfilter = {
|
if (linkfilter) settings.linkfilter = {
|
||||||
enabled: result.linkfilter?.enabled || false,
|
enabled: linkfilter.enabled || false,
|
||||||
silent: result.linkfilter?.silent || false,
|
silent: linkfilter.silent || false,
|
||||||
ignore: result.linkfilter?.channels || [],
|
ignore: linkfilter.channels || [],
|
||||||
bypass: result.linkfilter?.roles || [],
|
bypass: linkfilter.roles || [],
|
||||||
actions: [],
|
actions: [],
|
||||||
whitelist: result.linkfilter?.whitelist === true ? result.linkfilter.filter : [],
|
whitelist: linkfilter.whitelist === true ? linkfilter.filter : [],
|
||||||
blacklist: result.linkfilter?.whitelist === false ? result.linkfilter.filter : [],
|
blacklist: linkfilter.whitelist === false ? linkfilter.filter : [],
|
||||||
greylist: []
|
greylist: [],
|
||||||
|
whitelistMode: linkfilter.whitelist || false
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ignore) settings.ignore = {
|
if (ignore) settings.ignore = {
|
||||||
@ -334,7 +335,7 @@ class SettingsMigrator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (autorole) settings.autorole = autorole;
|
if (autorole) settings.autorole = autorole;
|
||||||
if (prefix) settings.prefix = prefix;
|
if (prefix) settings.textcommands = { prefix, enabled: false };
|
||||||
if (welcomer) {
|
if (welcomer) {
|
||||||
settings.welcomer.enabled = welcomer.enabled;
|
settings.welcomer.enabled = welcomer.enabled;
|
||||||
settings.welcomer.message = welcomer.message || null;
|
settings.welcomer.message = welcomer.message || null;
|
||||||
@ -398,7 +399,8 @@ class SettingsMigrator {
|
|||||||
silent: false,
|
silent: false,
|
||||||
bypass: result.invitefilter.roles,
|
bypass: result.invitefilter.roles,
|
||||||
enabled: result.invitefilter.enabled,
|
enabled: result.invitefilter.enabled,
|
||||||
actions: []
|
actions: [],
|
||||||
|
whitelist: []
|
||||||
};
|
};
|
||||||
const channels = Object.entries(invitefilter.channels || {});
|
const channels = Object.entries(invitefilter.channels || {});
|
||||||
for (const [id, value] of channels) {
|
for (const [id, value] of channels) {
|
||||||
|
Loading…
Reference in New Issue
Block a user