From 94bdb1985364a0a67d5cca633362f156545cc43d Mon Sep 17 00:00:00 2001 From: nolan Date: Sun, 17 May 2020 09:07:39 -0400 Subject: [PATCH] large permission changes and ping command change --- .../en_us/arguments/en_us_administrator.lang | 15 +- .../en_us/commands/en_us_administration.lang | 58 +++++- .../en_us/commands/en_us_utility.lang | 18 +- language/languages/en_us/en_us_modules.lang | 19 -- .../commands/administration/Grant.js | 37 ++-- .../commands/administration/Permissions.js | 187 +++++++++++++++++- .../commands/administration/Revoke.js | 42 ++-- .../components/commands/utility/Avatar.js | 2 +- .../components/commands/utility/Lookup.js | 110 +++++++++++ .../components/commands/utility/Ping.js | 4 +- .../components/observers/CommandHandler.js | 4 + structure/extensions/Message.js | 4 +- structure/interfaces/Command.js | 3 + 13 files changed, 415 insertions(+), 88 deletions(-) delete mode 100644 language/languages/en_us/en_us_modules.lang create mode 100644 structure/client/components/commands/utility/Lookup.js diff --git a/language/languages/en_us/arguments/en_us_administrator.lang b/language/languages/en_us/arguments/en_us_administrator.lang index d961b01..3144f3d 100644 --- a/language/languages/en_us/arguments/en_us_administrator.lang +++ b/language/languages/en_us/arguments/en_us_administrator.lang @@ -1,2 +1,15 @@ +//Grant Command + [A_CHANNEL_GRANT_DESCRIPTION] -Specify channels to grant specific permissions to. \ No newline at end of file +Specify channels to grant specific permissions to. + +//Revoke Command +[A_CHANNEL_REVOKE_DESCRIPTION] +Specify channels to revoke permissions from. + +//Permissions Command +[A_USER_PERMISSIONS_DESCRIPTION] +Enable viewing all user's permissions. + +[A_JSON_PERMISSIONS_DESCRIPTION] +Upload a raw JSON file of all of the permissions in the guild. \ No newline at end of file diff --git a/language/languages/en_us/commands/en_us_administration.lang b/language/languages/en_us/commands/en_us_administration.lang index ff72ef5..4808aeb 100644 --- a/language/languages/en_us/commands/en_us_administration.lang +++ b/language/languages/en_us/commands/en_us_administration.lang @@ -1,7 +1,8 @@ //Grant Command [C_GRANT_DESCRIPTION] -Grant roles or users permissions for commands or modules. +Grant roles or users permissions to use commands or modules. +To view all grantable permissions, use the command `{prefix}perms list`. [C_GRANT_RESOLVEERROR] Unable to find a role or member, view `{prefix}cmd grant` for more help. @@ -15,16 +16,14 @@ There was an issue pushing the permissions to the database. Contact a bot develo [C_GRANT_SUCCESS] Successfully granted **{resolveable}** the following permissions: {permissions} -[C_GRANT_SUCCESSALT]S +[C_GRANT_SUCCESSALT] in channel(s) {channels}. [C_GRANT_SUCCESSFAILED] -Some permissions have failed to add, likely because the {resolveable} already has the permissions or you did not supply valid permissions. +Some permissions failed to grant, likely because they already have the permissions or you did not supply valid permissions. [C_GRANT_FAILED] -Failed to grant the following permissions: {failed}. -This is likely because the {resolveable} already has the permissions or you did not supply valid permissions. - +Failed to grant the permissions provided, view `{prefix}cmd grant` for more help. //Revoke Command @@ -41,7 +40,52 @@ You must provide permissions to revoke, view `{prefix}cmd grant` for more help. [C_REVOKE_DATABASEERROR] There was an issue removing the permissions from the database. Contact a bot developer. +[C_REVOKE_SUCCESS] +Successfully revoked **{resolveable}** the following permissions: {removed} + +[C_REVOKE_SUCCESSALT] +in channel(s) {channels}. + +[C_REVOKE_SUCCESSFAILED] +Some permissions failed to revoke, likely because they did not have the permissions in the first place. + +[C_REVOKE_FAILED] +Failed to revoke the permissions provided, try double-checking the permissions with `{prefix}perms {resolveable}`. + //Permissions Command [C_PERMISSIONS_DESCRIPTION] -View permissions granted to roles or users. \ No newline at end of file +View permissions granted to roles or users. + +[C_PERMISSIONS_LIST] +You can **grant**/**revoke** the following permissions: {permissions}. + +[C_PERMISSIONS_SHOWTITLE] +switch({user}) { + case true: + "User Permissions" + break; + case false: + "Role Permissions" + break; +} + +[C_PERMISSIONS_SHOWDESCRIPTION] +An overview of all {resolve}'s permissions in the guild. If you would like to see an in-depth view of the role or user's permissions, use `{prefix}perms [user|role]`. + +[C_PERMISSIONS_MAXFIELDS] +:warning: **You have met the max amount of fields and you will need to use `{prefix}perms --json` to view them.** :warning: + +[C_PERMISSIONS_NOTFOUND] +Unable to find any roles or users with those arguments. + +[C_PERMISSIONS_JSON] +Attached the JSON-formatted permission file in the file below. +You may want to format this file for your viewing pleasure. + +[C_PERMISSIONS_GLOBAL] +**Global Permissions:** {permissions} +Global permissions can be used in all channels, but you can add specific channels if needed. + +[C_PERMISSIONS_GLOBALALT] +Channel-specific permissions are listed below. \ No newline at end of file diff --git a/language/languages/en_us/commands/en_us_utility.lang b/language/languages/en_us/commands/en_us_utility.lang index 0ee3c6b..2c8b87c 100644 --- a/language/languages/en_us/commands/en_us_utility.lang +++ b/language/languages/en_us/commands/en_us_utility.lang @@ -1,8 +1,5 @@ //Ping Command -[C_PING_RESPONSE] -Pong! - [C_PING_DESCRIPTION] Shows the millisecond delay between the bot and the discord server. @@ -73,5 +70,18 @@ Found {matches} matches, displaying {count} To search server members with similar names use `{prefix}user search ` //Avatar Command +[C_AVATAR_DESCRIPTION] +Fetches avatars for various users in different formats and sizes. + [C_AVATAR_FORMATERROR] -Unable to find an avatar with those arguments, try a different size or format. \ No newline at end of file +Unable to find an avatar with those arguments, try a different size or format. + +//Lookup Command +[C_LOOKUP_DESCRIPTION] +Looks up a discord invite code and returns the information of the invite. + +[C_LOOKUP_FAILEDMATCH] +Couldn't find a discord invite code, try again. + +[C_LOOKUP_NONEXISTANT] +Unable to find any data about that invite code. \ No newline at end of file diff --git a/language/languages/en_us/en_us_modules.lang b/language/languages/en_us/en_us_modules.lang deleted file mode 100644 index cf67afd..0000000 --- a/language/languages/en_us/en_us_modules.lang +++ /dev/null @@ -1,19 +0,0 @@ -[M_UTILITY_NAME] -Utility - -[M_MODERATION_NAME] -Moderation - -[M_DEVELOPER_NAME] -Developer - -[M_ADMINISTRATOR_NAME] -Administrator - -[M_INFORMATION_NAME] -Information - -[M_MUSIC_NAME] -Music - -[ diff --git a/structure/client/components/commands/administration/Grant.js b/structure/client/components/commands/administration/Grant.js index da2d3d0..6e84caf 100644 --- a/structure/client/components/commands/administration/Grant.js +++ b/structure/client/components/commands/administration/Grant.js @@ -14,9 +14,10 @@ class GrantCommand extends Command { "\"Server Moderators\" module:moderation", "@nolan#2887 command:kick" ], - memberPermissions: ['ADMINISTRATOR', 'MANAGE_SERVER'], + // memberPermissions: ['ADMINISTRATOR', 'MANAGE_GUILD'], showUsage: true, guildOnly: true, + grantable: true, arguments: [ { name: 'channel', @@ -34,8 +35,6 @@ class GrantCommand extends Command { async execute(message, { params, args }) { - // console.log(args.channel); - const _permissions = await message.guild.permissions(); const [ parse, ...perms ] = params; @@ -54,18 +53,16 @@ class GrantCommand extends Command { let parsed = []; if(perms.join(' ') === 'all') { - parsed = this.client.registry.components.filter(c=>c.grantable && c.type === 'command').map(c=>c.resolveable); + parsed = this.client.registry.components.filter(c=>c.type === 'command').map(c=>c.resolveable); //filter for grantable } else { for(const perm of perms) { const search = permissions.filter(filterInexact(perm)).first(); - if(!search) failed.push(perm); + if(!search) continue; if(search.type === 'module') { for(const component of search.components.values()) { if(component.type === 'command') parsed.push(component.resolveable); - //add check for grantable } } else { - //add check for grantable parsed.push(search.resolveable); } } @@ -79,32 +76,31 @@ class GrantCommand extends Command { } let existing = _permissions[resolveable.id]; - let pushed = []; - let failed = []; + let granted = []; if(args.channel) { for(const channel of args.channel.value) { const existingChannel = existing.channels[channel.id]; if(existingChannel) { for(const perm of parsed) { if(existingChannel.includes(perm)) { - failed.push(perm); + continue; } else { existingChannel.push(perm); - pushed.push(perm); + granted.push(perm); } } } else { existing.channels[channel.id] = parsed; - pushed.concat(parsed) + granted = [ ...granted, ...parsed ]; } } } else { for(const perm of parsed) { if(existing.global.includes(perm)) { - failed.push(perm); + continue; } else { existing.global.push(perm); - pushed.push(perm); + granted.push(perm); } } } @@ -124,18 +120,17 @@ class GrantCommand extends Command { } }); } catch(error) { - await message.respond(message.format('C_GRANT_DATABASEERROR'), { emoji: 'failure' }); - return undefined; + await message.respond(message.format('C_GRANT_DATABASEERROR'), { emoji: 'failure' }); + return undefined; } - if(pushed.length > 0) { - return await message.respond(stripIndents`${message.format('C_GRANT_SUCCESS', { resolveable: resolveable.name || resolveable.user?.tag, permissions: pushed.map(p=>`\`${p}\``).join(', ') })}${args.channel ? ` ${message.format('C_GRANT_SUCCESSALT', { channels: args.channel.value.map(c=>`\`#${c.name}\``).join(', ')})}`: '.'} - ${failed.length > 0 ? message.format('C_GRANT_SUCCESSFAILED', { resolveable: resolveable.user ? 'user' : 'role' }) : ''}`, { emoji: 'success' }); + if(granted.length > 0) { + await message.respond(stripIndents`${message.format('C_GRANT_SUCCESS', { permissions: granted.map(g=>`\`${g}\``).join(', '), resolveable: resolveable.user ? resolveable.user.tag : resolveable.name })}${args.channel ? ` ${message.format('C_GRANT_SUCCESSALT', { channels: args.channel.value.map(c=>`\`#${c.name}\``).join(', ')})}` : '.'} + ${granted.length < parsed.length ? message.format('C_GRANT_SUCCESSFAILED'): ''}`, { emoji: 'success' }); } else { - return await message.respond(message.format('C_GRANT_FAILED', { failed: failed.map(f=>`\`${f}\``).join(', '), resolveable: resolveable.user ? 'user' : 'role' }), { emoji: 'failure' }) + await message.respond(message.format('C_GRANT_FAILED', { resolveable: resolveable.user ? resolveable.user.tag : resolveable.name }), { emoji: 'failure' }); } - } async _parseResolveable(message, resolveable) { diff --git a/structure/client/components/commands/administration/Permissions.js b/structure/client/components/commands/administration/Permissions.js index b0fccfe..4b67a00 100644 --- a/structure/client/components/commands/administration/Permissions.js +++ b/structure/client/components/commands/administration/Permissions.js @@ -1,40 +1,211 @@ +const { Role, MessageAttachment } = require('discord.js'); const { Command } = require('../../../../interfaces/'); const { stripIndents } = require('common-tags'); -class GrantCommand extends Command { +class PermissionsCommand extends Command { constructor(client) { super(client, { name: 'permissions', module: 'administration', - usage: "", + usage: "", aliases: [ 'perms', 'permission', 'perm' ], examples: [ + "list", "Server Moderators", "@nolan#2887" ], - memberPermissions: ['ADMINISTRATOR', 'MANAGE_SERVER'], + arguments: [ + { + name: 'user', + aliases: ['users'], + type: 'BOOLEAN', + types: ['VERBAL', 'FLAG'], + default: true + }, + { + name: 'json', + aliases: ['raw'], + type: 'BOOLEAN', + types: ['VERBAL', 'FLAG'], + default: true + } + ], + // memberPermissions: ['ADMINISTRATOR', 'MANAGE_GUILD'], guildOnly: true }); } - async execute(message) { + async execute(message, { params, args }) { - await message.guild.permissions(); + const permissions = await message.guild.permissions(); + if(args.json) { + await this._displayRaw(message, permissions); + return undefined; + } - message.respond(`\`\`\`js -${JSON.stringify(message.guild._permissions)}\`\`\``); + if(params.length === 0) { + await this._showPermissions(message, Boolean(args.user)); + return undefined; + } + + if(params[0] === 'list') { + await this._listAvailablePermissions(message); + return undefined; + } else { + const parameters = params.join(' '); + const resolveable = await this._parseResolveable(message, parameters); + const permission = permissions[resolveable?.id || parameters]; + if(!permission) { + await message.respond(message.format('C_PERMISSIONS_NOTFOUND'), { emoji: 'failure' }); + return undefined; + } + + const embed = { + author: { + name: `${resolveable?.user?.tag || resolveable?.tag || resolveable?.name || parameters} Permissions`, + // icon_url: resolveable?.user?.displayAvatarURL() || resolveable?.displayAvatarURL() || message.guild.iconURL() + }, + description: `${message.format('C_PERMISSIONS_GLOBAL', { permissions: permissions.global.length > 0 ? this._displayNames(permission.global).map(p=>`\`${p}\``).join(', ') : "`N/A`" })} ${Object.values(permission.channels).length > 0 ? message.format('C_PERMISSIONS_GLOBALALT') : ''}`, + fields: [] + }; + + let update = false; + for(const [channelId, perms] of Object.entries(permission.channels)) { + const channel = this.client.resolver.resolveChannels(channelId, message.guild, true)[0]; + if(!channel) { + delete permission.channels[channelId]; + update = true; + continue; + } else { + if(embed.fields.length === 25) { + embed.description += `\n${message.format('C_PERMISSIONS_MAXFIELDS')}`; + break; + } + embed.fields.push({ + name: `#${channel.name}`, + value: this._displayNames(perms).map(p=>`\`${p}\``).join(', ') + }); + } + } + if(update) { + delete permissions._id + try { + await this.client.transactionHandler.send({ + provider: 'mongodb', + request: { + type: 'updateOne', + collection: 'permissions', + query: { + guildId: message.guild.id + }, + data: permissions + } + }); + } catch(error) { + this.client.logger.error(`Error removing channel permissions to ${message.guild.id}:\n${error.stack || error}`); + } + } + + return await message.embed(embed); + + } + + } + + async _showPermissions(message, user = false) { + const embed = { + author: { + name: message.format('C_PERMISSIONS_SHOWTITLE', { user }, true), + icon_url: message.guild.iconURL() + }, + description: message.format('C_PERMISSIONS_SHOWDESCRIPTION', { resolve: user ? 'user' : 'role' }), + fields: [] + }; + + const permissions = message.guild._permissions; + for(const [id, value] of Object.entries(permissions)) { + if(id === '_id' || id === 'guildId') continue; + const item = await this.client.resolver[user ? 'resolveMemberAndUser' : 'resolveRoles'](id, message.guild); //dont kill me + if(item instanceof Role && user) continue; + else if(!user && !(item instanceof Role)) continue; + if(embed.fields.length === 25) { + embed.description += `\n${message.format('C_PERMISSIONS_MAXFIELDS')}`; + break; + } + const name = item?.user?.tag || item?.tag || item?.name || id; //please dont kill me again + const channels = Object.values(value.channels).length; + embed.fields.push({ + name, + value: stripIndents`${this._displayNames(value.global).map(n=>`\`${n}\``).join('\n')} + ${channels > 0 ? `\`..${channels} channel${channels === 1 ? '' : 's'}\`` : ''}` + }); + } + + return await message.embed(embed); + + } + + async _listAvailablePermissions(message) { + + const components = this.client.registry.components.filter(c=>(c.type === 'command' && c.grantable) || (c.type === 'module' && c.components.some(c=>c.type === 'command' && c.grantable))) + .sort((a, b) => a - b); + + return await message.respond(message.format('C_PERMISSIONS_LIST', { permissions: components.map(c => `\`${c.resolveable}\``).join(', ') }), { emoji: 'success' }); + + } + + async _parseResolveable(message, resolveable) { + let parsed = await this.client.resolver.resolveRoles(resolveable, message.guild); + if(!parsed) { + parsed = await this.client.resolver.resolveMembers(resolveable, message.guild); + if(!parsed) { + parsed = await this.client.resolver.resolveUsers(resolveable); + if(!parsed) return null; + } + } + return parsed[0]; + } + + async _displayRaw(message, permissions) { + + const string = JSON.stringify(permissions); + const attachment = new MessageAttachment(Buffer.from(string), "permissions.json"); + + return await message.respond(message.format('C_PERMISSIONS_JSON'), { emoji: 'success', attachments: [ attachment ] }) + + } + + _displayNames(permissions) { + + const modules = this.client.registry.components.filter(c=>c.type === 'module'); + let names = []; + + let temp = []; + for(const module of modules.values()) { + for(const component of module.components.filter(c=>c.type === 'command').values()) { + if(permissions.includes(component.resolveable)) { + temp.push(component.resolveable); + } + } + temp.length === module.components.filter(c=>c.type === 'command').size + ? names.push(module.resolveable) + : names = names.concat(temp); + temp = []; + } + + return names; } } -module.exports = GrantCommand; \ No newline at end of file +module.exports = PermissionsCommand; \ No newline at end of file diff --git a/structure/client/components/commands/administration/Revoke.js b/structure/client/components/commands/administration/Revoke.js index c520dca..fe00dc9 100644 --- a/structure/client/components/commands/administration/Revoke.js +++ b/structure/client/components/commands/administration/Revoke.js @@ -1,3 +1,6 @@ +const { User, GuildMember } = require('discord.js'); +const { stripIndents } = require('common-tags') + const { Command } = require('../../../../interfaces/'); class RevokeCommand extends Command { @@ -13,7 +16,7 @@ class RevokeCommand extends Command { "@nolan#2887 command:kick", "132620781791346688 moderation" ], - memberPermissions: ['ADMINISTRATOR'], + // memberPermissions: ['ADMINISTRATOR', 'MANAGE_GUILD'], showUsage: true, guildOnly: true, arguments: [ @@ -107,30 +110,10 @@ class RevokeCommand extends Command { } } - //check for deletion, saves DB space. - //NOTE: DO NOT REMOVE THE _PERMISSIONS VARIABLE. - console.log(permission.global.length, Object.keys(permission.channels).length); - if(permission.global.length === 0 - && Object.keys(permission.channels).length === 0) { - try { - const blah = await this.client.transactionHandler.send({ - provider: 'mongodb', - request: { - type: 'remove', - collection: 'permissions', - query: { - guildId: message.guild.id - } - } - }); - console.log(blah); - } catch(error) { - this.client.logger.warn(`Attempted to delete collection permissions:${message.guild.id} but failed.`); - } - } - delete _permissions._id; //some bullshit.. + //check for deletion, saves DB space. + //NOTE: DO NOT REMOVE THE _PERMISSIONS VARIABLE. if(permission.global.length === 0 && Object.keys(permission.channels).length === 0) { try { await this.client.transactionHandler.send({ @@ -165,8 +148,19 @@ class RevokeCommand extends Command { } } - + const name = resolveable instanceof GuildMember + ? resolveable?.user?.tag + : resolveable instanceof User + ? resolveable?.tag + : resolveable?.name; + if(removed.length > 0) { + await message.respond(stripIndents`${message.format('C_REVOKE_SUCCESS', { removed: removed.map(r=>`\`${r}\``).join(', '), resolveable: name || parsed })}${args.channel ? ` ${message.format('C_REVOKE_SUCCESSALT', { channels: args.channel.value.map(c=>`\`#${c.name}\``).join(', ')})}` : '.'} + ${removed.length < parsed.length ? message.format('C_REVOKE_SUCCESSFAILED'): ''}`, { emoji: 'success' }); + } else { + await message.respond(message.format('C_REVOKE_FAILED', { resolveable: name || parsed }), { emoji: 'failure' }); + } + } async _parseResolveable(message, resolveable) { diff --git a/structure/client/components/commands/utility/Avatar.js b/structure/client/components/commands/utility/Avatar.js index 9477e01..ec73c82 100644 --- a/structure/client/components/commands/utility/Avatar.js +++ b/structure/client/components/commands/utility/Avatar.js @@ -41,7 +41,7 @@ class AvatarCommand extends Command { if (!user) user = message.author; let avatar = null; try { - avatar = user.displayAvatarURL({ format: args.format?.value || 'webp', size: args.size?.value || 512, dynamic: true }); + avatar = user.displayAvatarURL({ format: args.format?.value || 'webp', size: args.size?.value || 128, dynamic: true }); } catch(error) { message.respond(message.format('C_AVATAR_FORMATERROR'), { emoji: 'failure' }); return undefined; diff --git a/structure/client/components/commands/utility/Lookup.js b/structure/client/components/commands/utility/Lookup.js new file mode 100644 index 0000000..671ad18 --- /dev/null +++ b/structure/client/components/commands/utility/Lookup.js @@ -0,0 +1,110 @@ +const fetch = require('node-fetch'); + +const { Command } = require('../../../../interfaces/'); + +//Apparently hit ratelimits pretty damn quick and doesn't expire often. +class LookupCommand extends Command { + + constructor(client) { + + super(client, { + name: 'lookup', + module: 'utility', + usage: "", + showUsage: true, + parameterType: 'PLAIN', + examples: [ + "SvJgtEj", + "discord.gg/SvJgtEj" + ], + restricted: true, //For now + throttling: { + usages: 1, + duration: 30 + } + }); + + this.client = client; + + + } + + async execute(message, { params }) { + + const regex = /discord(?:app\.com\/invite|\.gg(?:\/invite)?)\/([\w-]{2,255})/i; + const match = regex.exec(params); + + let code = null; + if(match && match[1]) { + code = match[1]; + } else { + const restrict = /([\w-]{2,255})/i.exec(params); + if(restrict && restrict[1]) { + code = restrict[1]; + } else { + await message.respond(message.format('C_LOOKUP_FAILEDMATCH')); + return undefined; + } + } + + let data = null; + try { + const request = await fetch(`https://discord.com/api/invite/${code}`); + data = await request.json(); + if(data.code && data.message) { + await message.respond(message.format('C_LOOKUP_NONEXISTANT')); + return undefined; + } + } catch(error) { + await message.respond(message.format('C_LOOKUP_NONEXISTANT')); + return undefined; + } + + let fields = []; + + if(data.inviter) { + fields.push({ + name: "Inviter", + value: `${data.inviter.username}#${data.inviter.discriminator} \`(${data.inviter.id})\``, + inline: true + }); + } + + if(data.channel) { + fields.push({ + name: "Default Channel", + value: `#${data.channel.name} \`(${data.channel.id})\``, + inline: true + }); + } + + if(data.guild.features.length > 0) { + fields.push({ + name: "Features", + value: data.guild.features.map(f=>`\`${f}\``).join(', '), + inline: true, + }); + } + + const embed = { + author: { + name: `${data.guild.name} (${data.guild.id})`, + icon_url: `https://cdn.discordapp.com/icons/${data.guild.id}/${data.guild.icon}.webp` + }, + thumbnail: { + url: data.guild.splash ? `https://cdn.discordapp.com/splashes/${data.guild.id}/${data.guild.splash}.webp` : null + }, + description: data.guild.description || null, + fields, + footer: { + text: `https://discord.gg/${data.code}` + } + }; + + return message.embed(embed); + + } + +} + +module.exports = LookupCommand; \ No newline at end of file diff --git a/structure/client/components/commands/utility/Ping.js b/structure/client/components/commands/utility/Ping.js index 88cdba2..a9ee54c 100644 --- a/structure/client/components/commands/utility/Ping.js +++ b/structure/client/components/commands/utility/Ping.js @@ -16,7 +16,9 @@ class PingCommand extends Command { async execute(message) { const ping = this.client.ws.ping.toFixed(0); - return message.respond(`${message.format('C_PING_RESPONSE')} \`${ping}ms\``, { emoji: 'success' }); + const number = (ping/40).toFixed(0); + const repeat = number > 1 ? number : 1; + return message.respond(`P${'o'.repeat(repeat)}ng! \`${ping}ms\``, { emoji: 'success' }); } } diff --git a/structure/client/components/observers/CommandHandler.js b/structure/client/components/observers/CommandHandler.js index c83b76d..f6513ab 100644 --- a/structure/client/components/observers/CommandHandler.js +++ b/structure/client/components/observers/CommandHandler.js @@ -296,6 +296,10 @@ class CommandHandler extends Observer { const fff = {}; parsedArguments.map(a=>fff[a.name] = a); + if(command.parameterType === 'PLAIN') { + params = params.join(' '); + } + return { parsedArguments: fff, newArgs: params }; } diff --git a/structure/extensions/Message.js b/structure/extensions/Message.js index e05ffa9..a8342f0 100644 --- a/structure/extensions/Message.js +++ b/structure/extensions/Message.js @@ -78,7 +78,7 @@ const Message = Structures.extend('Message', (Message) => { } - async respond(str, opts = {}) { + async respond(str, opts = { attachments: [] }) { if(typeof str === 'string') { if(opts.emoji) { @@ -90,7 +90,7 @@ const Message = Structures.extend('Message', (Message) => { } //console.log(str) - this._pending = await this.channel.send(str); + this._pending = await this.channel.send(str, { files: opts.attachments }); return this._pending; } diff --git a/structure/interfaces/Command.js b/structure/interfaces/Command.js index 32b9e3b..3119f71 100644 --- a/structure/interfaces/Command.js +++ b/structure/interfaces/Command.js @@ -28,6 +28,9 @@ class Command extends Component { this.archivable = opts.archivable === undefined ? false : Boolean(opts.archivable); this.arguments = opts.arguments || []; + this.parameterType = opts.parameterType || 'SPLIT'; //SPLIT or PLAIN, PLAIN = string, SPLIT = split into array, includes quotes + + this.grantable = Boolean(opts.grantable); this.clientPermissions = opts.clientPermissions || []; this.memberPermissions = opts.memberPermissions || [];