diff --git a/language/languages/en_us/commands/en_us_information.lang b/language/languages/en_us/commands/en_us_information.lang index 455598f..72f56a8 100644 --- a/language/languages/en_us/commands/en_us_information.lang +++ b/language/languages/en_us/commands/en_us_information.lang @@ -61,8 +61,11 @@ View data about the server. **Owner:** <@{owner}> **Member count:** {members} +**Boost tier:** {tier} +**Boosters:** {boosters} **Date created:** {createdAt} **Server ID:** {id} +**Shard ID:** {shard} **Channels:** Text {tc} / Voice {vc} **Server voice region:** {region} diff --git a/language/languages/en_us/en_us_general.lang b/language/languages/en_us/en_us_general.lang index 107bd7e..bcb5804 100644 --- a/language/languages/en_us/en_us_general.lang +++ b/language/languages/en_us/en_us_general.lang @@ -154,6 +154,9 @@ The command **{command}** can only be run by developers. The command **{command}** is currently throttled. *You can use this command again in `{remaining}` seconds.* +[I_CHANNELIGNORE_ERROR] +This channel is ignored by the bot, this should not be sending. + //Moderation Manager [MODERATIONMANAGER_INFRACTION_MAXTARGETS] You can only specify up to `{maxTargets}` unique {type}s, try again. diff --git a/language/languages/en_us/settings/en_us_moderation.lang b/language/languages/en_us/settings/en_us_moderation.lang index e0d54b8..486cd77 100644 --- a/language/languages/en_us/settings/en_us_moderation.lang +++ b/language/languages/en_us/settings/en_us_moderation.lang @@ -105,6 +105,15 @@ Successfully set member nicknames to log to {emoji_text-channel}**{changed}**. [S_MEMBERLOG_DESCRIPTION] Configure member logging for your server. +**Usable tags:** +{mention} - mentions the user +{tag} - username#discriminator +{user} - username +{guildsize} - member count of the server +{guildname} - name of the server +{accage} - age of the account +{id} - ID of the account + [S_MEMBERLOGS_TOGGLE] Successfully turned member logging **{changed}**. diff --git a/language/languages/en_us/settings/en_us_utility.lang b/language/languages/en_us/settings/en_us_utility.lang index 04538b0..a1512e3 100644 --- a/language/languages/en_us/settings/en_us_utility.lang +++ b/language/languages/en_us/settings/en_us_utility.lang @@ -14,6 +14,26 @@ Successfully set the guild description to [S_INDEX_TOGGLE] Successfully toggled guild indexing `{toggle}` +//GUILD WELCOMER +[S_WELCOMER_DESCRIPTION] +Configure a message that is sent to new members upon join. + +**Usable tags:** +{mention} - mentions the user +{tag} - username#discriminator +{user} - username +{guildsize} - member count of the server +{guildname} - name of the server +{accage} - age of the account +{id} - ID of the account + +[S_WELCOMER_TOGGLE] +Successfully toggled the welcomer `{toggle}`. + +[S_WELCOMER_SET] +Successfully set the welcomer message to +`{change}` + //guildPrefix Setting [S_GUILDPREFIX_DESCRIPTION] diff --git a/structure/client/Dispatcher.js b/structure/client/Dispatcher.js index 4e766ab..de95795 100644 --- a/structure/client/Dispatcher.js +++ b/structure/client/Dispatcher.js @@ -10,7 +10,7 @@ class Dispatcher { const observers = this.client.registry.components .filter((c) => c.type === 'observer' && !c.disabled) - .sort((a, b) => b.priority - a.priority); + .sort((a, b) => a.priority - b.priority); for(const observer of observers.values()) { for(const [hook, func] of observer.hooks) { diff --git a/structure/client/Resolver.js b/structure/client/Resolver.js index d68633f..202e3c6 100644 --- a/structure/client/Resolver.js +++ b/structure/client/Resolver.js @@ -80,7 +80,7 @@ class Resolver { add: ['add', '+'], set: ['set', '='], remove: ['remove', 'delete', '-'], - reset: ['clear', 'reset'], + reset: ['clear', 'reset', 'default'], off: ['off', 'disable', 'false', 'no', 'n', 'f'], on: ['on', 'enable', 'true', 'yes', 'y', 't'] }; diff --git a/structure/client/components/commands/utility/Guild.js b/structure/client/components/commands/information/Guild.js similarity index 81% rename from structure/client/components/commands/utility/Guild.js rename to structure/client/components/commands/information/Guild.js index 0d986a7..442b17c 100644 --- a/structure/client/components/commands/utility/Guild.js +++ b/structure/client/components/commands/information/Guild.js @@ -1,4 +1,4 @@ -const { Command } = require('../../../../interfaces/'); +const { Command } = require('../../../../interfaces'); class GuildCommand extends Command { @@ -6,7 +6,7 @@ class GuildCommand extends Command { super(client, { name: 'guild', - module: 'utility', + module: 'information', aliases: [ 'server' ] @@ -40,7 +40,10 @@ class GuildCommand extends Command { id: guild.id, name: guild.name, region: guild.region, - members: guild.memberCount + members: guild.memberCount, + boosters: guild.premiumSubscriptionCount, + tier: guild.premiumTier, + shard: guild.shardID }), thumbnail: { url: guild.iconURL() diff --git a/structure/client/components/commands/utility/User.js b/structure/client/components/commands/information/User.js similarity index 97% rename from structure/client/components/commands/utility/User.js rename to structure/client/components/commands/information/User.js index a6bfdd9..ffff713 100644 --- a/structure/client/components/commands/utility/User.js +++ b/structure/client/components/commands/information/User.js @@ -1,4 +1,4 @@ -const { Command } = require('../../../../interfaces/'); +const { Command } = require('../../../../interfaces'); const similarity = require('similarity'); class UserCommand extends Command { @@ -7,7 +7,7 @@ class UserCommand extends Command { super(client, { name: 'user', - module: 'utility', + module: 'information', description: 'Display information about user.', guildOnly: true, arguments: [ diff --git a/structure/client/components/inhibitors/ChannelIgnore.js b/structure/client/components/inhibitors/ChannelIgnore.js new file mode 100644 index 0000000..97ddae3 --- /dev/null +++ b/structure/client/components/inhibitors/ChannelIgnore.js @@ -0,0 +1,35 @@ +const { Inhibitor } = require('../../../interfaces/'); + +class ChannelIgnore extends Inhibitor { + + constructor(client) { + + super(client, { + name: 'channelIgnore', + priority: 5, + guild: true + }); + + } + + execute(message, command) { + + if(message.member.admin) return super._succeed(); + + const { guild, member, channel } = message, + setting = guild._settings.ignore, + roles = member._roles; + + if(!setting.enabled) return super._succeed(); + if(setting.channels.includes(channel.id)) + for(const role of roles) { + if(setting.roleBypass.includes(role)) return super._succeed(); + return super._fail({ error: true, silent: true }); + } + return super._succeed(); + + } + +} + +module.exports = ChannelIgnore; \ No newline at end of file diff --git a/structure/client/components/inhibitors/Restricted.js b/structure/client/components/inhibitors/Restricted.js index 12a89ce..b1cef87 100644 --- a/structure/client/components/inhibitors/Restricted.js +++ b/structure/client/components/inhibitors/Restricted.js @@ -13,7 +13,7 @@ class Restricted extends Inhibitor { } execute(message, command) { - if(command.restricted && !this.client._options.bot.owners.includes(message.author.id)) { + if(command.restricted && !message.author.developer) { return super._fail(); } return super._succeed(); diff --git a/structure/client/components/observers/CommandHandler.js b/structure/client/components/observers/CommandHandler.js index d01a916..31de500 100644 --- a/structure/client/components/observers/CommandHandler.js +++ b/structure/client/components/observers/CommandHandler.js @@ -384,6 +384,7 @@ class CommandHandler extends Observer { async handleCommand(message) { +<<<<<<< HEAD const inhibitors = await this._handleInhibitors(message); const silent = inhibitors.filter((i) => i.inhibitor.silent); @@ -391,6 +392,11 @@ class CommandHandler extends Observer { if(nonsilent.length === 0 && silent.length > 0) return undefined; if(nonsilent.length > 0) return this.handleError(message, { type: 'inhibitor', ...nonsilent[0] }); +======= + const inhibitor = await this._handleInhibitors(message); + //console.log(inhibitor); + if(inhibitor.error) return this.handleError(message, { type: 'inhibitor', ...inhibitor }); +>>>>>>> 33c6f57150e4727e216796dc63e8dd5ceb587070 const resolved = await message.resolve(); if(resolved.error) { @@ -420,8 +426,13 @@ class CommandHandler extends Observer { const reasons = (await Promise.all(promises)).filter((p) => p.error); // Filters out inhibitors with only errors. if(reasons.length === 0) return []; +<<<<<<< HEAD reasons.sort((a, b) => b.inhibitor.priority - a.inhibitor.priority); // Sorts inhibitor errors by most important. return reasons; +======= + reasons.sort((a, b) => a.inhibitor.priority - b.inhibitor.priority); // Sorts inhibitor errors by most important. + return reasons[0]; +>>>>>>> 33c6f57150e4727e216796dc63e8dd5ceb587070 } @@ -577,7 +588,8 @@ class CommandHandler extends Observer { } }; - return message.respond(await messages[error.type](error), { emoji: 'failure' }); + //return this.client.rateLimiter.limitSend(message.channel, await messages[error.type](error)); + return message.limitedRespond(await messages[error.type](error), { emoji: 'failure', limit: 10, utility: error.type }); } diff --git a/structure/client/components/observers/GuildLogging.js b/structure/client/components/observers/GuildLogging.js index fe37fa6..db89019 100644 --- a/structure/client/components/observers/GuildLogging.js +++ b/structure/client/components/observers/GuildLogging.js @@ -7,7 +7,18 @@ const CONSTANTS = { YELLOW: 15120384, // message edit LIGHT_BLUE: 11337726, // message pin BLUE: 479397 - } + }, + IMAGES: { + PREMIUM_LIMIT: 2, + UPLOAD_LIMIT: { + '0': 8, + '1': 8, + '2': 50, + '3': 100 + }, + MB_DIVIDER: 1024*1024 + }, + WEEK: 7 * 24 * 60 * 60 }; class GuildLogger extends Observer { @@ -37,6 +48,85 @@ class GuildLogger extends Observer { async storeAttachment(message) { + const { guild, member, author, channel } = message; + if(!guild || author.bot) return; + if(!message.attachments.size) return; + console.log('Store call') + + const settings = await guild.settings(), + setting = settings.messageLog, + roles = member._roles, + { ignoredRoles } = setting; + + //if(guild._settings.premium < CONSTANTS.IMAGES.PREMIUM_LIMIT) return; + if(!setting.attachments || setting.ignoredChannels.includes(channel.id)) return; + if(setting.ignoredRoles.length && roles.length) + for(const role of ignoredRoles) + if(roles.includes(role)) return; + + console.log('Can store') + + const attachments = message.attachments.values(); + for(const attachment of attachments) { + + const TH = this.client.transactionHandler; + const { size, name, id } = attachment; + const fsize = size/CONSTANTS.IMAGES.MB_DIVIDER // File size in MB + if(fsize > CONSTANTS.IMAGES.UPLOAD_LIMIT[guild.premiumTier]) continue; + + const buffer = await Util.downloadAsBuffer(attachment.url).catch(err => { this.client.logger.error(err); return null; }); + if(!buffer) return; + const data = { + buffer, + id + }; + + try { + //TODO: test this + //const start = Date.now(); + const result = await TH.send({ + provider: 'mongodb', + request: { + type: 'insertOne', + collection: 'attachment_logs', + data + } + }); + + //console.log(`Took ${Date.now()-start}ms to insert image.`); + //console.log(result); + + const metadata = { + database_ID: result.insertedId, + id, + guild: guild.id, + message: message.id, + author: author.id, + name, + size, + timestamp: Math.floor(Date.now()/1000), + removeAt: Math.floor(Date.now()/1000 + guild._settings.premium * CONSTANTS.WEEK * 0.25) + } + + //console.log(metadata); + + await TH.send({ + provider: 'mongodb', + request: { + type: 'insertOne', + collection: 'attachment_logs_index', + data: metadata + } + }); + + //console.log(`Took ${Date.now()-start}ms to insert entire entry.`); + + } catch (err) { + this.client.logger.error('Something went wrong with storing image to db:\n' + err.stack); + } + + } + } //TODO: Figure this thing out, this should be called from messageDelete and rawMessageDelete if any attachments are present @@ -67,7 +157,7 @@ class GuildLogger extends Observer { const perms = logChannel.permissionsFor(guild.me); if(!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL')) return; - if (ignoredRoles && member._roles.length) + if (ignoredRoles.length && member._roles.length) for (const role of ignoredRoles) if (member._roles.includes(role)) return; @@ -235,14 +325,15 @@ class GuildLogger extends Observer { } _replaceTags(text, member) { - const { user } = member; + const { user, guild } = member; return text .replace(/\{mention\}/g, `<@${member.id}>`) - .replace(/\{tag\}/g, `${Util.escapeMarkdown(user.tag)}`) - .replace(/\{user\}/g, `${user.username}`) - .replace(/\{guildsize\}/g, `${guild.memberCount}`) - .replace(/\{accage\}/g, `${this.client.resolver.timeAgo(Date.now()/1000 - user.createdTimestamp/1000)}`) //.replace(/a/, '1') - .replace(/\{id\}/g, `${user.id}`) + .replace(/\{tag\}/g, Util.escapeMarkdown(user.tag)) + .replace(/\{user\}/g, Util.escapeMarkdown(user.username)) + .replace(/\{guildsize\}/g, guild.memberCount) + .replace(/\{guildname\}/g, guild.name) + .replace(/\{accage\}/g, this.client.resolver.timeAgo(Date.now()/1000 - user.createdTimestamp/1000)) //.replace(/a/, '1') + .replace(/\{id\}/g, user.id) .trim(); } diff --git a/structure/client/components/observers/UtilityHook.js b/structure/client/components/observers/UtilityHook.js new file mode 100644 index 0000000..ed47c46 --- /dev/null +++ b/structure/client/components/observers/UtilityHook.js @@ -0,0 +1,67 @@ +const { Observer } = require('../../../interfaces/'); + +const CONSTANTS = {}; + +class UtilityHook extends Observer { + + constructor(client) { + + super(client, { + name: 'utility', + priority: 3 + }); + + this.hooks = [ + ['guildMemberAdd', this.welcome.bind(this)], + ['guildMemberAdd', this.autorole.bind(this)] + ] + + } + + async stickyRole(member) { + + const { guild } = member; + const settings = await guild.settings(); + const setting = settings.stickyRole; + if(!setting.enabled) return; + + } + + async autorole(member) { + + const { guild } = member; + const settings = await guild.settings(); + const setting = settings.autorole; + if(!setting.enabled) return; + + } + + async welcome(member) { + + const { guild, user } = member; + const settings = await guild.settings(); + const setting = settings.welcomer; + if(!setting.enabled) return; + + const channel = await user.createDM(); + const message = this._replaceTags(setting.message, member); + await channel.send(message).catch(); + + } + + _replaceTags(text, member) { + const { user, guild } = member; + return text + .replace(/\{mention\}/g, `<@${member.id}>`) + .replace(/\{tag\}/g, Util.escapeMarkdown(user.tag)) + .replace(/\{user\}/g, Util.escapeMarkdown(user.username)) + .replace(/\{guildsize\}/g, guild.memberCount) + .replace(/\{guildname\}/g, guild.name) + .replace(/\{accage\}/g, this.client.resolver.timeAgo(Date.now()/1000 - user.createdTimestamp/1000)) //.replace(/a/, '1') + .replace(/\{id\}/g, user.id) + .trim(); + } + +} + +module.exports = UtilityHook; \ No newline at end of file diff --git a/structure/client/components/settings/moderation/DmInfraction.js b/structure/client/components/settings/moderation/DmInfraction.js index 490aa4a..ff9145b 100644 --- a/structure/client/components/settings/moderation/DmInfraction.js +++ b/structure/client/components/settings/moderation/DmInfraction.js @@ -24,8 +24,6 @@ class DmInfractionSetting extends Setting { } }); - this.client = client; - } async handle(message, args) { diff --git a/structure/client/components/settings/moderation/MemberLogs.js b/structure/client/components/settings/moderation/MemberLogs.js index 7127833..bd91cb5 100644 --- a/structure/client/components/settings/moderation/MemberLogs.js +++ b/structure/client/components/settings/moderation/MemberLogs.js @@ -58,8 +58,6 @@ class MemberLogsSetting extends Setting { ] }); - this.client = client; - } async handle(message, args) { diff --git a/structure/client/components/settings/moderation/MessageLog.js b/structure/client/components/settings/moderation/MessageLog.js index 8b4de70..ca83515 100644 --- a/structure/client/components/settings/moderation/MessageLog.js +++ b/structure/client/components/settings/moderation/MessageLog.js @@ -36,8 +36,6 @@ class MessageLogsSetting extends Setting { } }); - this.client = client; - } async handle(message, params) { @@ -248,6 +246,11 @@ class MessageLogsSetting extends Setting { value: await guild.resolveChannel(setting?.channel) || '`N/A`', inline: true }, + { + name: '》Log attachments', + value: setting?.attachments || false, + inline: true + }, { name: '》Ignored Roles', value: roles?.map((r) => r.name).join(', ') || '`N/A`', diff --git a/structure/client/components/settings/moderation/ModerationLog.js b/structure/client/components/settings/moderation/ModerationLog.js index ca8a3c7..a2e9f28 100644 --- a/structure/client/components/settings/moderation/ModerationLog.js +++ b/structure/client/components/settings/moderation/ModerationLog.js @@ -32,8 +32,6 @@ class ModerationLogsSetting extends Setting { } }); - this.client = client; - } async handle(message, params) { diff --git a/structure/client/components/settings/moderation/ModerationPoints.js b/structure/client/components/settings/moderation/ModerationPoints.js index 69ef189..b01ac7e 100644 --- a/structure/client/components/settings/moderation/ModerationPoints.js +++ b/structure/client/components/settings/moderation/ModerationPoints.js @@ -51,8 +51,6 @@ class ModerationPointsSetting extends Setting { } }); - this.client = client; - } async handle(message, args) { diff --git a/structure/client/components/settings/moderation/Mute.js b/structure/client/components/settings/moderation/Mute.js index 97df9ec..b73ad2d 100644 --- a/structure/client/components/settings/moderation/Mute.js +++ b/structure/client/components/settings/moderation/Mute.js @@ -88,8 +88,6 @@ class MuteSetting extends Setting { } } }); - - this.client = client; } diff --git a/structure/client/components/settings/moderation/NicknameLogs.js b/structure/client/components/settings/moderation/NicknameLogs.js index ee2451c..251e3a4 100644 --- a/structure/client/components/settings/moderation/NicknameLogs.js +++ b/structure/client/components/settings/moderation/NicknameLogs.js @@ -26,8 +26,6 @@ class NicknameLogs extends Setting { } }); - this.client = client; - } async handle(message, params) { diff --git a/structure/client/components/settings/moderation/VoiceLogs.js b/structure/client/components/settings/moderation/VoiceLogs.js index 1da5663..5040194 100644 --- a/structure/client/components/settings/moderation/VoiceLogs.js +++ b/structure/client/components/settings/moderation/VoiceLogs.js @@ -26,8 +26,6 @@ class VoiceLogSettings extends Setting { } }); - this.client = client; - } async handle(message, params) { diff --git a/structure/client/components/settings/utility/Autorole.js b/structure/client/components/settings/utility/Autorole.js index 76febbb..458dee2 100644 --- a/structure/client/components/settings/utility/Autorole.js +++ b/structure/client/components/settings/utility/Autorole.js @@ -26,8 +26,6 @@ class AutoroleSetting extends Setting { custom: true }); - this.client = client; - } async handle(message, params) { diff --git a/structure/client/components/settings/utility/GuildIndexing.js b/structure/client/components/settings/utility/GuildIndexing.js index b434f22..08c8798 100644 --- a/structure/client/components/settings/utility/GuildIndexing.js +++ b/structure/client/components/settings/utility/GuildIndexing.js @@ -29,8 +29,6 @@ class DescriptionSetting extends Setting { custom: true }); - this.client = client; - } async handle(message, params) { diff --git a/structure/client/components/settings/utility/GuildPrefix.js b/structure/client/components/settings/utility/GuildPrefix.js index b5c351d..5d0cb7f 100644 --- a/structure/client/components/settings/utility/GuildPrefix.js +++ b/structure/client/components/settings/utility/GuildPrefix.js @@ -20,8 +20,6 @@ class GuildPrefixSetting extends Setting { }, custom: true }); - - this.client = client; } diff --git a/structure/client/components/settings/utility/IgnoreChannels.js b/structure/client/components/settings/utility/IgnoreChannels.js index 57fa658..2fa91c4 100644 --- a/structure/client/components/settings/utility/IgnoreChannels.js +++ b/structure/client/components/settings/utility/IgnoreChannels.js @@ -30,8 +30,6 @@ class IgnoreSetting extends Setting { custom: true }); - this.client = client; - } async handle(message, params) { diff --git a/structure/client/components/settings/utility/PermissionType.js b/structure/client/components/settings/utility/PermissionType.js index 74c9a09..7c3349d 100644 --- a/structure/client/components/settings/utility/PermissionType.js +++ b/structure/client/components/settings/utility/PermissionType.js @@ -26,8 +26,6 @@ class PermissionTypeSetting extends Setting { 'permissiontype reset' ] }); - - this.client = client; } diff --git a/structure/client/components/settings/utility/Welcomer.js b/structure/client/components/settings/utility/Welcomer.js new file mode 100644 index 0000000..bdb5f42 --- /dev/null +++ b/structure/client/components/settings/utility/Welcomer.js @@ -0,0 +1,77 @@ +const { Setting } = require('../../../../interfaces/'); + +class WelcomerSetting extends Setting { + + constructor(client) { + + super(client, { + name: 'welcomer', + module: 'utility', + aliases: [ + + ], + usage: '', + examples: [ + 'welcomer Welcome to {guildname}!', + 'welcomer ', + 'welcomer reset' + ], + guarded: false, + resolve: 'GUILD', + default: { + welcomer: { + message: 'Welcome to {guildname}!', + enabled: false + } + }, + custom: true + }); + + } + + async handle(message, params) { + + const { guild } = message; + const setting = guild._settings[this.index] || this.default[this.index]; + const { resolver } = this.client; + const response = await resolver.resolveMethod(params); + const langParams = {}; + let index = null; + + if(resolver.resolveBoolean(params[0]) !== null) { + setting.enabled = resolver.resolveBoolean(params[0]); + index = 'S_WELCOMER_TOGGLE'; + langParams.toggle = message.format('ON_OFF_TOGGLE', { toggle: setting.enabled }, true) + } else { + setting.message = message.content.replace(guild.prefix, '').replace(message._caller, '').replace(message._settingCaller, '').trim(); + index = 'S_WELCOMER_SET'; + langParams.change = setting.message; + } + + await message.guild._updateSettings({ [this.index]: setting }); + return { + error: false, + msg: message.format(index, langParams) + }; + + } + + async fields(guild) { + const setting = guild._settings[this.index] || this.default[this.index]; + return [ + { + name: '》Enabled', + value: setting.enabled, + inline: false + }, + { + name: '》Message', + value: setting.message.substring(0,1021) + setting.message.length > 1021 ? '...' : '', + inline: false + } + ] + } + +} + +module.exports = WelcomerSetting; \ No newline at end of file diff --git a/structure/extensions/GuildMember.js b/structure/extensions/GuildMember.js index 636cfef..46818f7 100644 --- a/structure/extensions/GuildMember.js +++ b/structure/extensions/GuildMember.js @@ -33,6 +33,10 @@ const GuildMember = Structures.extend('GuildMember', (GuildMember) => { } + get admin() { + return this.user.developer || this.hasPermission('ADMINISTRATOR') || this.hasPermission('MANAGE_GUILD'); + } + get timeSinceCached() { return Date.now()-this._cached; } diff --git a/structure/extensions/Message.js b/structure/extensions/Message.js index a92d38b..4c14d93 100644 --- a/structure/extensions/Message.js +++ b/structure/extensions/Message.js @@ -1,7 +1,6 @@ const { Structures } = require('discord.js'); const escapeRegex = require('escape-string-regexp'); -const emojis = require('../../util/emojis.json'); const { Util, Emojis } = require('../../util/'); const { stripIndents } = require('common-tags') @@ -90,7 +89,7 @@ const Message = Structures.extend('Message', (Message) => { if(typeof str === 'string') { if(opts.emoji) { - const emoji = emojis[opts.emoji]; + const emoji = Emojis[opts.emoji]; if(!emoji) this.command.client.logger.warn(`Invalid emoji provided to command ${this.command.resolveable}: "${opts.emoji}".`); str = `${emoji} ${str}`; } @@ -103,10 +102,25 @@ const Message = Structures.extend('Message', (Message) => { } + async limitedRespond(str, opts = { attachments: [] }) { + + if(typeof str === 'string') { + if(opts.emoji) { + const emoji = Emojis[opts.emoji]; + if(!emoji) this.client.logger.warn(`Invalid emoji provided to command ${this.command.resolveable}: "${opts.emoji}".`); + str = `${emoji} ${str}`; + } + if(opts.reply) str = `<@!${this.author.id}> ${str}`; + } + + return this.client.rateLimiter.limitSend(this.channel, str, opts.limit, opts.utility); + + } + async edit(str, opts) { if(!this.editable) return null; if(typeof str === 'string') { - if(opts.emoji) str = `${emojis[opts.emoji]} ${str}`; + if(opts.emoji) str = `${Emojis[opts.emoji]} ${str}`; if(opts.reply) str = `<@!${this.author.id}> ${str}`; } return super.edit(str); @@ -114,7 +128,7 @@ const Message = Structures.extend('Message', (Message) => { async prompt(str, opts) { if(typeof str === 'string') { - if(opts.emoji) str = `${emojis[opts.emoji]} ${str}`; + if(opts.emoji) str = `${Emojis[opts.emoji]} ${str}`; if(opts.reply) str = `<@!${this.author.id}> ${str}`; } await this.channel.send(str); diff --git a/util/Util.js b/util/Util.js index 9cf5107..679589e 100644 --- a/util/Util.js +++ b/util/Util.js @@ -11,6 +11,15 @@ class Util { throw new Error("Class may not be instantiated."); } + static downloadAsBuffer(source) { + return new Promise((resolve, reject) => { + fetch(source).then(res => { + if(res.ok) resolve(res.buffer()); + else reject(res.statusText); + }); + }); + } + static readdirRecursive(directory) { const result = [];