diff --git a/src/commands/base.js b/src/commands/base.js index 822134f33..b31728099 100644 --- a/src/commands/base.js +++ b/src/commands/base.js @@ -25,6 +25,7 @@ class Command { * @property {string} [details] - A detailed description of the command and its functionality * @property {string[]} [examples] - Usage examples of the command * @property {boolean} [guildOnly=false] - Whether or not the command should only function in a guild channel + * @property {boolean} [dmOnly=false] - Whether or not the command should only function in a dm channel * @property {boolean} [ownerOnly=false] - Whether or not the command is usable only by an owner * @property {PermissionResolvable[]} [clientPermissions] - Permissions required by the client to use the command. * @property {PermissionResolvable[]} [userPermissions] - Permissions required by the user to use the command. @@ -133,6 +134,12 @@ class Command { */ this.guildOnly = Boolean(info.guildOnly); + /** + * Whether the command can only be run in a dm channel + * @type {boolean} + */ + this.dmOnly = Boolean(info.dmOnly); + /** * Whether the command can only be used by an owner * @type {boolean} @@ -305,6 +312,8 @@ class Command { switch(reason) { case 'guildOnly': return message.reply(`The \`${this.name}\` command must be used in a server channel.`); + case 'dmOnly': + return message.reply(`The \`${this.name}\` command must be used in a dm channel`); case 'nsfw': return message.reply(`The \`${this.name}\` command can only be used in NSFW channels.`); case 'permission': { @@ -419,7 +428,8 @@ class Command { */ isUsable(message = null) { if(!message) return this._globalEnabled; - if(this.guildOnly && message && !message.guild) return false; + if(this.guildOnly && !message.guild) return false; + if(this.dmOnly && message.channel.type !== 'dm') return false; const hasPermission = this.hasPermission(message); return this.isEnabledIn(message.guild) && hasPermission && typeof hasPermission !== 'string'; } diff --git a/src/extensions/message.js b/src/extensions/message.js index ddd24b1ca..43fdff4e1 100644 --- a/src/extensions/message.js +++ b/src/extensions/message.js @@ -138,7 +138,7 @@ module.exports = Structures.extend('Message', Message => { * @event CommandoClient#commandBlock * @param {CommandoMessage} message - Command message that the command is running from * @param {string} reason - Reason that the command was blocked - * (built-in reasons are `guildOnly`, `nsfw`, `permission`, `throttling`, and `clientPermissions`) + * (built-in reasons are `guildOnly`, `dmOnly`, `nsfw`, `permission`, `throttling`, and `clientPermissions`) * @param {Object} [data] - Additional data associated with the block. Built-in reason data properties: * - guildOnly: none * - nsfw: none @@ -149,6 +149,10 @@ module.exports = Structures.extend('Message', Message => { this.client.emit('commandBlock', this, 'guildOnly'); return this.command.onBlock(this, 'guildOnly'); } + if(this.command.dmOnly && this.channel.type !== 'dm') { + this.client.emit('commandBlock', this, 'dmOnly'); + return this.command.onBlock(this, 'dmOnly'); + } // Ensure the channel is a NSFW one if required if(this.command.nsfw && !this.channel.nsfw) { diff --git a/typings/index.d.ts b/typings/index.d.ts index 5813fcdc2..c7c3dd8be 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1,5 +1,5 @@ declare module 'discord.js-commando' { - import { Channel, Client, ClientOptions, Collection, DMChannel, Emoji, Guild, GuildChannel, GuildMember, GuildResolvable, Message, MessageAttachment, MessageEmbed, MessageMentions, MessageOptions, MessageAdditions, MessageReaction, PermissionResolvable, PermissionString, ReactionEmoji, Role, Snowflake, StringResolvable, TextChannel, User, UserResolvable, VoiceState, Webhook } from 'discord.js'; + import { Channel, Client, ClientOptions, Collection, DMChannel, Emoji, Guild, GuildChannel, GuildMember, GuildResolvable, Message, MessageAttachment, MessageEmbed, MessageMentions, MessageOptions, MessageAdditions, MessageReaction, PermissionResolvable, PermissionString, ReactionEmoji, Role, Snowflake, StringResolvable, TextChannel, User, UserResolvable, VoiceState, Webhook } from "discord.js"; export class Argument { private constructor(client: CommandoClient, info: ArgumentInfo); @@ -77,7 +77,8 @@ declare module 'discord.js-commando' { public groupID: string; public guarded: boolean; public hidden: boolean; - public guildOnly: boolean; + public guildOnly: boolean + public dmOnly: boolean; public memberName: string; public name: string; public nsfw: boolean; @@ -91,7 +92,7 @@ declare module 'discord.js-commando' { public isEnabledIn(guild: GuildResolvable, bypassGroup?: boolean): boolean; public isUsable(message: Message): boolean; public onBlock(message: CommandoMessage, reason: string, data?: Object): Promise; - public onBlock(message: CommandoMessage, reason: 'guildOnly' | 'nsfw'): Promise; + public onBlock(message: CommandoMessage, reason: 'dmOnly' | 'guildOnly' | 'nsfw'): Promise; public onBlock(message: CommandoMessage, reason: 'permission', data: { response?: string }): Promise; public onBlock(message: CommandoMessage, reason: 'clientPermissions', data: { missing: PermissionString[] }): Promise; public onBlock(message: CommandoMessage, reason: 'throttling', data: { throttle: Object, remaining: number }): Promise; @@ -229,7 +230,7 @@ declare module 'discord.js-commando' { on(event: string, listener: Function): this; on(event: 'commandBlock', listener: (message: CommandoMessage, reason: string, data?: Object) => void): this; - on(event: 'commandBlock', listener: (message: CommandoMessage, reason: 'guildOnly' | 'nsfw') => void): this; + on(event: 'commandBlock', listener: (message: CommandoMessage, reason: 'dmOnly' |'guildOnly' | 'nsfw') => void): this; on(event: 'commandBlock', listener: (message: CommandoMessage, reason: 'permission', data: { response?: string }) => void): this; on(event: 'commandBlock', listener: (message: CommandoMessage, reason: 'throttling', data: { throttle: Object, remaining: number }) => void): this; on(event: 'commandBlock', listener: (message: CommandoMessage, reason: 'clientPermissions', data: { missing: string }) => void): this; @@ -470,6 +471,7 @@ declare module 'discord.js-commando' { examples?: string[]; nsfw?: boolean; guildOnly?: boolean; + dmOnly?: boolean; ownerOnly?: boolean; clientPermissions?: PermissionResolvable[]; userPermissions?: PermissionResolvable[];