text based commands

This commit is contained in:
Erik 2022-07-27 12:32:01 +03:00
parent 58ea955cc5
commit 5e4736f97f
Signed by untrusted user: Navy.gif
GPG Key ID: 811EC0CD80E7E5FB
31 changed files with 593 additions and 321 deletions

View File

@ -90,6 +90,7 @@ class MessageWrapper {
async editReply(options) {
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);
}

View File

@ -50,8 +50,12 @@ class HistoryCommand extends SlashCommand {
minimum: 1,
flag: true
}, {
name: ['user', 'moderator'], //
description: ['User whose infractions to query, overrides channel if both are given', 'Query by moderator'],
name: 'user',
description: 'User whose infractions to query, overrides channel if both are given',
type: 'USER'
}, {
name: 'moderator',
description: 'Query by moderator',
type: 'USER',
flag: true
}, {

View File

@ -1,5 +1,5 @@
const { Util } = require("../../../../utilities");
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
class IgnoreSetting extends Setting {
@ -19,7 +19,7 @@ class IgnoreSetting extends Setting {
bypass: { ARRAY: 'GUILD_ROLE' }
},
commandOptions: [
new CommandOption({
{
name: 'list',
description: 'List to act on',
type: 'STRING',
@ -27,9 +27,9 @@ class IgnoreSetting extends Setting {
{ name: 'channels', value: 'channels' },
{ name: 'bypass', value: 'bypass' }
],
dependsOn: ['method']
}),
new CommandOption({
dependsOn: ['method']//, valueAsAlias: true, flag: true
},
{
name: 'method',
description: 'Method of modifying',
type: 'STRING',
@ -39,8 +39,8 @@ class IgnoreSetting extends Setting {
{ name: 'set', value: 'set' },
{ name: 'reset', value: 'reset' },
],
dependsOn: ['list']
})
dependsOn: ['list']//, valueAsAlias: true, flag: true
}
]
});

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require('../../../interfaces/');
const { Setting } = require('../../../interfaces/');
class PermissionType extends Setting {
@ -16,15 +16,16 @@ class PermissionType extends Setting {
type: 'STRING'
},
commandOptions: [
new CommandOption({
{
type: 'STRING',
name: 'type',
description: 'Where to read permissions from',
choices: [
{ name: 'discord', value: 'discord' },
{ name: 'both', value: 'both' },
{ name: 'grant', value: 'grant' }
]
})
}
]
});

View File

@ -1,5 +1,5 @@
const { Util } = require("../../../../utilities");
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
class ProtectionSetting extends Setting {
@ -21,7 +21,7 @@ class ProtectionSetting extends Setting {
enabled: 'BOOLEAN'
},
commandOptions: [
new CommandOption({
{
type: 'STRING',
name: 'type',
description: 'Select protection type',
@ -30,8 +30,8 @@ class ProtectionSetting extends Setting {
{ name: 'position', value: 'position' }
],
dependsOn: []
}),
new CommandOption({
},
{
type: 'STRING',
name: 'roles',
description: 'Method of modifying',
@ -42,12 +42,12 @@ class ProtectionSetting extends Setting {
{ name: 'reset', value: 'reset' },
],
dependsOn: []
}),
new CommandOption({
},
{
type: 'BOOLEAN',
name: 'enabled',
description: 'Whether setting is active or not'
})
}
]
});

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
class SilentSetting extends Setting {
@ -17,11 +17,11 @@ class SilentSetting extends Setting {
enabled: 'BOOLEAN'
},
commandOptions: [
new CommandOption({
type: 'BOOLEAN',
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'enabled',
description: 'Toggle state'
})
}
]
});

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
const Infractions = [
'NOTE',
'WARN',
@ -57,13 +57,13 @@ class DmInfraction extends Setting {
}
},
commandOptions: [
new CommandOption({
{
name: 'message',
description: 'Set the message for an infraction type',
type: 'STRING',
dependsOn: ['infraction']
}),
new CommandOption({
},
{
name: 'infraction',
description: 'Choose the infraction for which to modify the message',
type: 'STRING',
@ -71,8 +71,8 @@ class DmInfraction extends Setting {
return { name: inf, value: inf };
}),
dependsOn: ['message']
}),
new CommandOption({
},
{
name: 'infractions',
description: 'Modify the list of infractions that are sent',
type: 'STRING',
@ -82,15 +82,15 @@ class DmInfraction extends Setting {
{ name: 'set', value: 'set' },
{ name: 'reset', value: 'reset' },
]
}),
new CommandOption({
},
{
name: 'enabled',
description: 'Enable or disable the sending of infractions in DMs',
type: 'BOOLEAN'
}),
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'anonymous',
type: 'BOOLEAN',
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
description: 'Whether who issued the infraction is shown in moderation logs'
}
]

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
class MessageLog extends Setting {
@ -22,16 +22,16 @@ class MessageLog extends Setting {
types: { ARRAY: 'ERROR_TYPES' } // TODO: Error types
},
commandOptions: [
new CommandOption({
{
name: 'channel',
description: 'Channel in which to output logs',
type: 'TEXT_CHANNEL'
}),
new CommandOption({
},
{
name: 'enabled',
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) {
const { guild } = interaction;
if (opts.enabled?.value === false) setting.channel = null;
if (opts.channel) {
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']);
if (missingPerms.length) return {
error: true,

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
class MemberLog extends Setting {
@ -21,26 +21,26 @@ class MemberLog extends Setting {
leave: 'STRING'
},
commandOptions: [
new CommandOption({
{
name: 'enabled',
description: 'Enable/disable member logs',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'channel',
description: 'Select the log output channel',
type: 'TEXT_CHANNEL'
}),
new CommandOption({
},
{
name: 'join',
description: 'Set the join message',
type: 'STRING'
}),
new CommandOption({
type: 'STRING', flag: true
},
{
name: 'leave',
description: 'Set the leave message',
type: 'STRING'
})
type: 'STRING', flag: true
}
]
});

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
const { Util } = require('../../../../utilities');
class MessageLog extends Setting {
@ -26,22 +26,22 @@ class MessageLog extends Setting {
attachments: 'BOOLEAN'
},
commandOptions: [
new CommandOption({
{
name: 'channel',
description: 'Channel in which to output logs',
type: 'TEXT_CHANNEL'
}),
new CommandOption({
},
{
name: 'enabled',
description: 'Toggle logging on or off',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'attachments',
description: 'Whether to log attachments. PREMIUM TIER 1',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'list',
description: 'Select which list to modify',
type: 'STRING',
@ -50,8 +50,8 @@ class MessageLog extends Setting {
{ name: 'ignore', value: 'ignore' },
],
dependsOn: ['method']
}),
new CommandOption({
},
{
name: 'method',
description: 'Select which modification method to use',
type: 'STRING',
@ -62,7 +62,7 @@ class MessageLog extends Setting {
{ name: 'reset', value: 'reset' },
],
dependsOn: ['list']
}),
},
]
});
@ -82,7 +82,7 @@ class MessageLog extends Setting {
if (opts.channel) {
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']);
if (missingPerms.length) return {
error: true,

View File

@ -1,5 +1,5 @@
const { Infractions } = require("../../../../constants/Constants");
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
// [
// 'NOTE',
@ -44,17 +44,17 @@ class ModerationLog extends Setting {
}
},
commandOptions: [
new CommandOption({
{
name: 'enabled',
description: 'Enable/disable member logs',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'channel',
description: 'Logging channel',
type: 'TEXT_CHANNEL'
}),
new CommandOption({
},
{
name: 'infractions',
description: 'Modify the list of infractions that are sent',
type: 'STRING',
@ -64,10 +64,10 @@ class ModerationLog extends Setting {
{ name: 'set', value: 'set' },
{ name: 'reset', value: 'reset' },
]
}),
},
{
name: 'anonymous',
type: 'BOOLEAN',
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
description: 'Whether who issued the infraction is shown in moderation logs'
}
]

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
class Nicknames extends Setting {
@ -16,16 +16,16 @@ class Nicknames extends Setting {
channel: 'GUILD_TEXT'
},
commandOptions: [
new CommandOption({
{
name: 'enabled',
description: 'Toggle logging on or off',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'channel',
type: 'TEXT_CHANNEL',
description: 'Set the channel for nickname logging'
})
}
]
});
}

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
class Voice extends Setting {
@ -15,16 +15,16 @@ class Voice extends Setting {
channel: 'GUILD_TEXT'
},
commandOptions: [
new CommandOption({
{
name: 'enabled',
description: 'Toggle logging on or off',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'channel',
type: 'TEXT_CHANNEL',
description: 'Set the channel for voice join/leave logging'
})
}
]
});
}

View File

@ -1,5 +1,5 @@
const { Util } = require("../../../../utilities");
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
const Infractions = [
'WARN',
'MUTE',
@ -17,7 +17,7 @@ class Automod extends Setting {
super(client, {
name: 'automod',
description: 'Define automatic infraction escalation',
display: 'Automatic Moderation',
display: 'Automatic Infraction Escalation',
module: 'moderation',
default: {
enabled: false,
@ -36,17 +36,17 @@ class Automod extends Setting {
}
},
commandOptions: [
new CommandOption({
{
name: 'enabled',
description: 'Toggle state',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'useprevious',
description: 'Use the previously passed threshold if the point total lands between two thresholds',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'threshold',
description: 'The threshold at which to issue an infraction',
type: 'INTEGER',
@ -54,8 +54,8 @@ class Automod extends Setting {
maximum: 100,
dependsOn: ['infraction', 'length'],
dependsOnMode: 'OR'
}),
new CommandOption({
},
{
name: 'infraction',
description: 'The type of infraction to issue',
type: 'STRING',
@ -63,13 +63,13 @@ class Automod extends Setting {
return { name: inf, value: inf };
}),
dependsOn: ['threshold']
}),
new CommandOption({
},
{
name: 'length',
description: 'The duration for a tempban or a mute',
type: 'TIME',
dependsOn: ['threshold']
})
}
]
});
}

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
const { Util } = require("../../../../utilities");
class Grantable extends Setting {
@ -18,12 +18,12 @@ class Grantable extends Setting {
enabled: 'BOOLEAN'
},
commandOptions: [
new CommandOption({
type: 'BOOLEAN',
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'enabled',
description: 'Toggle state'
}),
new CommandOption({
},
{
name: 'roles',
description: '',
type: 'STRING',
@ -33,7 +33,7 @@ class Grantable extends Setting {
{ name: 'set', value: 'set' },
{ name: 'reset', value: 'reset' },
]
})
}
]
});
}

View File

@ -1,4 +1,4 @@
const { FilterSetting, CommandOption } = require('../../../interfaces/');
const { FilterSetting } = require('../../../interfaces/');
const { Util } = require("../../../../utilities");
class InviteFilterSetting extends FilterSetting {
@ -36,7 +36,7 @@ class InviteFilterSetting extends FilterSetting {
actions: { ARRAY: 'ACTION' }
},
commandOptions: [
new CommandOption({
{
type: 'STRING',
name: 'method',
description: 'Select which modification method to use',
@ -49,8 +49,8 @@ class InviteFilterSetting extends FilterSetting {
{ name: 'list', value: 'list' }
],
dependsOn: ['list']
}),
new CommandOption({
},
{
type: 'STRING',
name: 'list',
description: 'Select which list to modify',
@ -61,17 +61,17 @@ class InviteFilterSetting extends FilterSetting {
{ name: 'actions', value: 'actions' },
],
dependsOn: ['method']
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'enabled',
description: 'Toggle enable state'
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'silent',
description: 'Toggle silent operation'
})
}
]
});

View File

@ -1,4 +1,4 @@
const { FilterSetting, CommandOption } = require('../../../interfaces/');
const { FilterSetting } = require('../../../interfaces/');
const { Util } = require("../../../../utilities");
const { FilterPresets } = require('../../../../constants');
@ -43,7 +43,7 @@ class LinkFilterSetting extends FilterSetting {
actions: { ARRAY: 'ACTION' }
},
commandOptions: [
new CommandOption({
{
type: 'STRING',
name: 'method',
description: 'Select which modification method to use',
@ -56,8 +56,8 @@ class LinkFilterSetting extends FilterSetting {
{ name: 'list', value: 'list' }
],
dependsOn: ['list']
}),
new CommandOption({
},
{
type: 'STRING',
name: 'list',
description: 'Select which list to modify',
@ -71,22 +71,22 @@ class LinkFilterSetting extends FilterSetting {
{ name: 'presets', value: 'presets' }
],
dependsOn: ['method']
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'enabled',
description: 'Toggle enable state'
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'whitelist',
description: 'Toggle whitelist mode'
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'silent',
description: 'Toggle silent operation'
})
}
]
});

View File

@ -1,4 +1,4 @@
const { FilterSetting, CommandOption } = require('../../../interfaces/');
const { FilterSetting } = require('../../../interfaces/');
const { Util } = require("../../../../utilities");
class MentionFilter extends FilterSetting {
@ -28,27 +28,27 @@ class MentionFilter extends FilterSetting {
ignore: { ARRAY: 'GUILD_TEXT' }
},
commandOptions: [
new CommandOption({
{
name: 'enabled',
description: 'Toggle state',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'silent',
description: 'Whether the bot will respond in chat',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'unique',
description: 'Mentions for the same user count as one',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'limit',
description: 'How many mentions are allowed in a message',
type: 'INTEGER'
}),
new CommandOption({
},
{
type: 'STRING',
name: 'method',
description: 'Select which modification method to use',
@ -61,8 +61,8 @@ class MentionFilter extends FilterSetting {
{ name: 'list', value: 'list' }
],
dependsOn: ['list']
}),
new CommandOption({
},
{
type: 'STRING',
name: 'list',
description: 'Select which list to modify',
@ -72,7 +72,7 @@ class MentionFilter extends FilterSetting {
{ name: 'actions', value: 'actions' },
],
dependsOn: ['method']
}),
},
]
});
}

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
const { Util } = require("../../../../utilities");
const INFRACTIONS = ['WARN', 'MUTE', 'KICK', 'SOFTBAN', 'BAN', 'VCMUTE', 'VCKICK', 'VCBAN'];
@ -37,7 +37,7 @@ class ModerationPoints extends Setting {
multiplier: false
},
commandOptions: [
new CommandOption({
{
name: 'points',
description: 'Point value',
type: 'INTEGER',
@ -45,14 +45,14 @@ class ModerationPoints extends Setting {
dependsOnMode: 'OR',
minimum: 0,
maximum: 100
}),
new CommandOption({
},
{
name: 'expire',
description: 'How long the points are counted for',
type: 'TIME',
dependsOn: ['type']
}),
new CommandOption({
},
{
name: 'infraction',
description: 'Type of infraction',
type: 'STRING',
@ -61,23 +61,23 @@ class ModerationPoints extends Setting {
}),
dependsOn: ['points', 'expire'],
dependsOnMode: 'OR'
}),
new CommandOption({
},
{
name: 'enabled',
description: 'Toggle on or off',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'multiplier',
description: 'Use points as a multiplier for the expiration',
type: 'BOOLEAN'
}),
new CommandOption({
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
},
{
name: 'associate',
description: 'Associate a word within a reason to a point value',
type: 'STRING',
dependsOn: ['points']
}),
dependsOn: ['points'], flag: true
},
]
});
}

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require('../../../interfaces/');
const { Setting } = require('../../../interfaces/');
const { inspect } = require('util');
const { Util } = require("../../../../utilities");
@ -52,28 +52,28 @@ class MuteSetting extends Setting {
permanent: 'BOOLEAN'
},
commandOptions: [
new CommandOption({
type: 'STRING',
{
type: 'STRING', flag: true,
name: 'create',
description: 'Create a mute role, mutually exclusive with role'
}),
new CommandOption({
},
{
type: 'ROLE',
name: 'role',
description: 'Select the role to use for mutes, mutually exclusive with create'
}),
new CommandOption({
type: 'TIME',
},
{
type: 'TIME', flag: true,
name: 'default',
description: 'Set the default duration for mutes'
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'permanent',
description: 'Whether to allow permanent mutes or fall back to default mute duration'
}),
new CommandOption({
type: 'INTEGER',
},
{
type: 'INTEGER', flag: true,
name: 'type',
description: 'Select the type of mute behaviour',
choices: [ {
@ -89,7 +89,7 @@ class MuteSetting extends Setting {
name: 'Type 3 (Use Discord timeouts)',
value: 3
} ]
})
}
]
});
@ -187,7 +187,8 @@ class MuteSetting extends Setting {
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 {
index: 'SETTING_MUTE_ROLEMISSINGPERMISSION',
error: true
@ -251,7 +252,7 @@ class MuteSetting extends Setting {
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 });
continue;
}

View File

@ -23,7 +23,7 @@ class StaffSetting extends Setting {
}, {
name: 'enabled',
description: 'Whether the staff command is in use',
type: 'BOOLEAN'
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true
}]
});
}

View File

@ -1,5 +1,5 @@
/* eslint-disable camelcase */
const { FilterSetting, CommandOption } = require('../../../interfaces/');
const { FilterSetting } = require('../../../interfaces/');
const { Util } = require("../../../../utilities");
const { FilterPresets } = require('../../../../constants');
@ -44,7 +44,7 @@ class WordFilterSetting extends FilterSetting {
actions: { ARRAY: 'ACTION' }
},
commandOptions: [
new CommandOption({
{
type: 'STRING',
name: 'method',
description: 'Select which modification method to use',
@ -57,8 +57,8 @@ class WordFilterSetting extends FilterSetting {
{ name: 'list', value: 'list' }
],
dependsOn: ['list']
}),
new CommandOption({
},
{
type: 'STRING',
name: 'list',
description: 'Select which list to modify',
@ -73,17 +73,17 @@ class WordFilterSetting extends FilterSetting {
{ name: 'actions', value: 'actions' },
],
dependsOn: ['method']
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'enabled',
description: 'Toggle enable state'
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'silent',
description: 'Toggle silent operation'
})
}
]
});
@ -136,7 +136,7 @@ class WordFilterSetting extends FilterSetting {
if (params.length && invalid.length) index += '_SOME';
} else if (list === 'presets') {
for (const word of words) {
if (FilterPresets.regex[word]) params.push(FilterPresets.regex[word]);
if (FilterPresets.regex[word]) params.push(...FilterPresets.regex[word]);
else invalid.push(word);
}
list = 'regex';
@ -147,7 +147,7 @@ class WordFilterSetting extends FilterSetting {
if (!params.length) {
if (['roles', 'channels'].includes(list.value))
return { error: true, index: 'RESOLVE_FAIL', params: { type: list === 'bypass' ? 'roles' : 'channels' } };
return { error: true, index };
return { error: true, index: 'SETTING_WORDFILTER_INVALID' };
}
const { modified } = this[method](setting[list], params.map((o) => o.id || o));
return { index, params: { updated: list, modified: params.filter((o) => modified.includes(o.id || o)).map((o) => o.name || o).join('__, __'), invalid: invalid.join('`, `') } };

View File

@ -1,4 +1,4 @@
const { FilterSetting, CommandOption } = require('../../../interfaces/');
const { FilterSetting } = require('../../../interfaces/');
const { Util } = require("../../../../utilities");
class WordWatcher extends FilterSetting {
@ -10,6 +10,7 @@ class WordWatcher extends FilterSetting {
description: 'Flag messages for potentially offensive content instead of deleting automatically',
module: 'moderation',
default: {
enabled: false,
channel: null,
words: [],
regex: [],
@ -18,7 +19,7 @@ class WordWatcher extends FilterSetting {
actions: []
},
commandOptions: [
new CommandOption({
{
type: 'STRING',
name: 'method',
description: 'Select which modification method to use',
@ -31,8 +32,8 @@ class WordWatcher extends FilterSetting {
{ name: 'list', value: 'list' }
],
dependsOn: ['list']
}),
new CommandOption({
},
{
type: 'STRING',
name: 'list',
description: 'Select which list to modify',
@ -44,12 +45,17 @@ class WordWatcher extends FilterSetting {
{ name: 'actions', value: 'actions' },
],
dependsOn: ['method']
}),
new CommandOption({
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'enabled',
description: 'Toggle enable state'
},
{
name: 'channel',
type: 'TEXT_CHANNEL',
description: 'Where to output flagged messages'
})
description: 'Where to output flagged messages',
}
]
});
}

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
const { Util } = require("../../../../utilities");
class Autorole extends Setting {
@ -18,7 +18,7 @@ class Autorole extends Setting {
enabled: 'BOOLEAN'
},
commandOptions: [
new CommandOption({
{
type: 'STRING',
name: 'roles',
description: 'Modification method for roles',
@ -30,12 +30,12 @@ class Autorole extends Setting {
{ name: 'edit', value: 'edit' },
{ name: 'list', value: 'list' }
]
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'enabled',
description: 'Toggle enable state'
})
}
]
});
}

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
const { Util } = require("../../../../utilities");
class Autorole extends Setting {
@ -18,7 +18,7 @@ class Autorole extends Setting {
enabled: 'BOOLEAN'
},
commandOptions: [
new CommandOption({
{
type: 'STRING',
name: 'roles',
description: 'Modification method for roles',
@ -30,12 +30,12 @@ class Autorole extends Setting {
{ name: 'edit', value: 'edit' },
{ name: 'list', value: 'list' }
]
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'enabled',
description: 'Toggle enable state'
})
}
],
premium: 1
});

View File

@ -1,4 +1,4 @@
const { Setting, CommandOption } = require("../../../interfaces");
const { Setting } = require("../../../interfaces");
class Autorole extends Setting {
@ -17,16 +17,16 @@ class Autorole extends Setting {
enabled: 'BOOLEAN'
},
commandOptions: [
new CommandOption({
{
type: 'STRING',
name: 'message',
description: 'Set the welcome message'
}),
new CommandOption({
type: 'BOOLEAN',
},
{
type: 'BOOLEAN', flag: true, valueOptional: true, defaultValue: true,
name: 'enabled',
description: 'Toggle enable state'
})
}
]
});
}

View File

@ -1,5 +1,7 @@
/* eslint-disable camelcase */
const { ChannelType } = require("discord.js");
const Constants = {
CommandOptionTypes: {
SUB_COMMAND: 1,
@ -28,7 +30,8 @@ const Constants = {
ROLE: 8,
MENTIONABLE: 9,
NUMBER: 10,
FLOAT: 10
FLOAT: 10,
POINTS: 4
},
ChannelTypes: {
TEXT_CHANNEL: 0,
@ -36,12 +39,17 @@ const Constants = {
}
};
const PointsReg = /^([-+]?[0-9]+) ?(points|point|pts|pt|p)$/iu;
class CommandOption {
constructor(options = {}) {
this._options = options;
this.name = options.name;
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.required = Boolean(options.required);
@ -52,8 +60,10 @@ class CommandOption {
if (options.options)
for (const opt of options.options) {
// console.log(opt);
if (opt instanceof CommandOption) this.options.push(opt);
else if (opt.name instanceof Array) {
if (opt instanceof CommandOption) {
opt.client = this.client;
this.options.push(opt);
} else if (opt.name instanceof Array) {
const { name: names, description, type, dependsOn, ...opts } = opt;
for (const name of names) {
// console.log(name);
@ -69,9 +79,12 @@ class CommandOption {
if (dependsOn instanceof Array) {
_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.
@ -83,32 +96,47 @@ class CommandOption {
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.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;
// 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
}
usage(guild) {
const name = `${this.name.toUpperCase()} [${this.type}]`;
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;
const format = (...args) => guild ? guild.format(...args) : this.client.format(...args);
if (this.type === 'SUB_COMMAND_GROUP') {
value = this.options.map((opt) => {
const usage = opt.usage(guild);
const usage = opt.usage(guild, true);
return `__${usage.name.replace('》', '').trim()}__\n${usage.value}`;
}).join('\n\n');
} else if (this.type === 'SUB_COMMAND') {
if (!this.options.length) value = guild.format('GENERAL_NO_ARGS');
else value = this.options.map((opt) => opt.usage(guild).value).join('\n');
if (!this.options.length) value = format('GENERAL_NO_ARGS');
else value = this.options.map((opt) => opt.usage(guild, true).value).join('\n');
} 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)
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)
value += `\n${guild.format('GENERAL_DEPENDSON', { dependencies: this.dependsOn.join('`, `') })}`;
value += `\n${format('GENERAL_DEPENDSON', { dependencies: this.dependsOn.join('`, `') })}`;
if (this.minimum !== undefined)
value += `\nMIN: \`${this.minimum}\``;
if (this.maximum !== undefined) {
@ -130,20 +158,268 @@ class CommandOption {
* @return {CommandOption}
* @memberof CommandOption
*/
clone(value) {
clone(_rawValue, guild, slashOption = false) {
return new CommandOption({
name: this.name, type: this.type,
minimum: this.minimum, maximum: this.maximum,
dependsOn: this.dependsOn, dependsOnMode: this.dependsOnMode,
_rawValue: value, strict: this.strict
...this._options, _rawValue, guild, slashOption
});
}
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 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 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 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 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 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 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 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 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.resomveMember(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() {
return {
name: this.name,
type: this.type,
options: []
options: this.options.map((opt) => opt.raw)
};
}

View File

@ -7,9 +7,8 @@ const Component = require("./Component.js");
// Imports to enable JSDocs typing
// eslint-disable-next-line no-unused-vars
const InteractionWrapper = require("../client/wrappers/InteractionWrapper.js");
const CommandOption = require('./CommandOption.js');
// eslint-disable-next-line no-unused-vars
// const { DiscordClient } = require("../DiscordClient.js");
const { DiscordClient } = require("../DiscordClient.js");
const TypeResolves = ['USER', 'GUILD'];
@ -70,29 +69,9 @@ class Setting extends Component {
this.default = { [this.name]: options.default || {} };
this.definitions = options.definitions || {}; // Used for the API for field definitions
this.commandOptions = [];
this.commandOptions = options.commandOptions || [];
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.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({
name: `${guild.format(`GENERAL_OPTIONS`)}`,
value: options.map(
(opt) => {
let msg = `**${opt.name} [${opt.type}]:** ${opt.description}`;
if (opt.choices.length)
msg += `\n__${guild.format('GENERAL_CHOICES')}__: ${opt.choices.map((choice) => choice.name).join(', ')}`;
if (opt.dependsOn.length)
msg += `\n${guild.format('GENERAL_DEPENDSON', { dependencies: opt.dependsOn.join('`, `') })}`;
if (opt.minimum !== undefined)
msg += `\nMIN: \`${opt.minimum}\``;
if (opt.maximum !== undefined) {
const newline = opt.minimum !== undefined ? ', ' : '\n';
msg += `${newline}MAX: \`${opt.maximum}\``;
}
return msg;
}
).join('\n\n')
value: options.map((opt) => opt.usage(guild, true)).map((f) => f.value).join('\n\n')
// value: options.map(
// (opt) => {
// let msg = `**${opt.name} [${opt.type}]:** ${opt.description}`;
// if (opt.choices.length)
// msg += `\n__${guild.format('GENERAL_CHOICES')}__: ${opt.choices.map((choice) => choice.name).join(', ')}`;
// if (opt.dependsOn.length)
// msg += `\n${guild.format('GENERAL_DEPENDSON', { dependencies: opt.dependsOn.join('`, `') })}`;
// if (opt.minimum !== undefined)
// msg += `\nMIN: \`${opt.minimum}\``;
// if (opt.maximum !== undefined) {
// const newline = opt.minimum !== undefined ? ', ' : '\n';
// msg += `${newline}MAX: \`${opt.maximum}\``;
// }
// return msg;
// }
// ).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');
const response = await invoker.promptMessage(
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') };
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);
if (['cancel', 'abort', 'exit'].includes(content)) return {
error: true,
message: invoker.format('ERR_CANCEL')
content: invoker.format('ERR_CANCEL')
};
else if (!content.length) return { error: true, index: 'SETTING_NOCONTENT' };
@ -241,7 +221,8 @@ class Setting extends Component {
for (const param of params) {
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);
}

View File

@ -51,8 +51,10 @@ class Command extends Component {
this.options = [];
if (options.options) for (const opt of options.options) {
if (opt instanceof CommandOption) this.options.push(opt);
else if (opt.name instanceof Array) {
if (opt instanceof CommandOption) {
opt.client = client;
this.options.push(opt);
} else if (opt.name instanceof Array) {
// Allows easy templating of subcommands that share arguments
const { name: names, description, type, ...opts } = opt;
for (const name of names) {
@ -64,9 +66,9 @@ class Command extends Component {
_type = type[index];
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) => {
@ -107,7 +109,11 @@ class Command extends Component {
const fields = [];
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 (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 required = [this.resolveable, ...this.memberPermissions];
fields.push({
name: `${guild.format('GENERAL_PERMISSIONS')}`,
name: `${format('GENERAL_PERMISSIONS')}`,
value: `\`${required.join('`, `')}\``
});
}
@ -135,7 +141,7 @@ class Command extends Component {
author: {
name: `${this.name} [module:${this.module.name}]`
},
description: guild.format(`COMMAND_${this.name.toUpperCase()}_HELP`),
description: format(`COMMAND_${this.name.toUpperCase()}_HELP`),
fields
});

View File

@ -4,6 +4,7 @@ class ModerationCommand extends SlashCommand {
constructor(client, opts) {
const flag = true;
let baseOptions = [
{
name: 'users',
@ -13,28 +14,32 @@ class ModerationCommand extends SlashCommand {
strict: true
}, {
name: 'points',
type: 'INTEGER',
type: 'POINTS',
description: 'The amount of points to assign to the infraction',
minimum: 0,
maximum: 100
}, {
name: 'expiration',
type: 'TIME',
description: 'How long until the points expire'
description: 'How long until the points expire',
flag
}, {
name: 'prune',
type: 'INTEGER',
description: 'How many messages to prune',
minimum: 2,
maximum: 100
maximum: 100,
flag
}, {
name: 'force',
type: 'BOOLEAN',
description: 'Whether to override automod'
description: 'Whether to override automod',
flag, valueOptional: true, defaultValue: true
}, {
name: 'silent',
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',
type: 'STRING',
@ -42,7 +47,6 @@ class ModerationCommand extends SlashCommand {
}
];
// Probably temporary
if(!opts.memberPermissions) throw new Error(`MISSING PERMS ${opts.name}`);
if (opts.skipOptions) for (const opt of opts.skipOptions) {

View File

@ -10,26 +10,16 @@ class SettingsCommand extends SlashCommand {
super(client, {
...options,
guildOnly: true,
memberPermissions: ['ManageGuild']
});
/*
{
name: 'settings',
description: "Configure the bot's behaviour in your server",
module: 'administration',
memberPermissions: ['ManageGuild'],
options: [
],
guildOnly: true
}
*/
this.options.push(new CommandOption({
type: 'SUB_COMMAND',
name: 'list',
description: 'List available settings'
}));
{
type: 'SUB_COMMAND',
name: 'list',
description: 'List available settings'
}
]
});
this.build();
}
@ -50,9 +40,12 @@ class SettingsCommand extends SlashCommand {
name: setting.name,
description: setting.description,
type: setting.commandType, //'SUB_COMMAND',
options: setting.commandOptions
options: setting.commandOptions,
client: this.client
});
this.options.push(subCommand);
// Overwrite the setting options with the built CommandOption structures
setting.commandOptions = subCommand.options;
}
// 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.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({
emoji: 'failure',
index: 'SETTING_MISSING_CLIENTPERMISSIONS',