From 11556c0b3b0317341da49875d072f732a054f2f1 Mon Sep 17 00:00:00 2001 From: SpaceEEC Date: Fri, 21 Jul 2017 02:27:19 +0200 Subject: [PATCH] Moved all error strings to src/errors/messages and a few other things (#1695) * Added missing error messages As well as `Guild#setRolePosition` and `Guild#setChannelPosition`'s first arg validation And fixed a typo in `Guild#setChannelPosition` `roles` -> `channels` * Reverted collection and Util constructors * Removed leftover messages Should have been in the second commit. * It's a single invalid permission and removed unused flag error * Fix INVALID_TOKEN -> TOKEN_INVALID as of #1703 --- src/client/ClientManager.js | 2 +- src/errors/Messages.js | 21 +++++++++++++++++---- src/structures/ClientUserSettings.js | 5 +++-- src/structures/Guild.js | 23 +++++++++++++---------- src/structures/GuildChannel.js | 3 ++- src/structures/GuildMember.js | 6 +++--- src/structures/Message.js | 4 ++-- src/structures/MessageReaction.js | 3 ++- src/structures/User.js | 3 ++- src/structures/VoiceChannel.js | 3 ++- src/util/Util.js | 4 ++-- 11 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/client/ClientManager.js b/src/client/ClientManager.js index 4b7f0102b..3ffc82e7c 100644 --- a/src/client/ClientManager.js +++ b/src/client/ClientManager.js @@ -38,7 +38,7 @@ class ClientManager { connectToWebSocket(token, resolve, reject) { this.client.emit(Constants.Events.DEBUG, `Authenticated using token ${token}`); this.client.token = token; - const timeout = this.client.setTimeout(() => reject(new Error('INVALID_TOKEN')), 1000 * 300); + const timeout = this.client.setTimeout(() => reject(new Error('TOKEN_INVALID')), 1000 * 300); this.client.api.gateway.get().then(res => { const protocolVersion = Constants.DefaultOptions.ws.version; const gateway = `${res.url}/?v=${protocolVersion}&encoding=${WebSocketConnection.ENCODING}`; diff --git a/src/errors/Messages.js b/src/errors/Messages.js index bd0c10a32..eda968dcb 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -13,8 +13,7 @@ const Messages = { WS_CONNECTION_EXISTS: 'There is already an existing WebSocket connection.', WS_NOT_OPEN: (data = 'data') => `Websocket not open to send ${data}`, - PERMISSIONS_INVALID: 'Invalid permission string or number.', - PERMISSIONS_INVALID_FLAG: 'Invalid bitfield flag string or number', + PERMISSION_INVALID: 'Invalid permission string or number.', RATELIMIT_INVALID_METHOD: 'Unknown rate limiting method.', @@ -26,6 +25,8 @@ const Messages = { SHARDING_IN_PROCESS: 'Shards are still being spawned', SHARDING_ALREADY_SPAWNED: count => `Already spawned ${count} shards`, + SHARD_MESSAGE_FAILED: 'Failed to send message to master process.', + COLOR_RANGE: 'Color must be within the range 0 - 16777215 (0xFFFFFF).', COLOR_CONVERT: 'Unable to convert color to a number.', @@ -39,7 +40,8 @@ const Messages = { FILE_NOT_FOUND: file => `File could not be found: ${file}`, USER_STATUS: 'User status must be a string', - SHARD_MESSAGE_FAILED: 'Failed to send message to master process.', + USER_NOT_CACHED: 'User is not cached. Use Client.fetchUser first.', + USER_NO_DMCHANNEL: 'No DM Channel exists!', VOICE_INVALID_HEARTBEAT: 'Tried to set voice heartbeat but no valid interval was specified.', VOICE_USER_MISSING: 'Couldn\'t resolve the user to create stream.', @@ -50,6 +52,7 @@ const Messages = { VOICE_TOKEN_ABSENT: 'Token not provided from voice server packet.', VOICE_SESSION_ABSENT: 'Session ID not supplied.', VOICE_INVALID_ENDPOINT: 'Invalid endpoint received.', + VOICE_NO_BROWSER: 'Voice connections are not available in browsers.', OPUS_ENGINE_MISSING: 'Couldn\'t find an Opus engine.', @@ -71,7 +74,7 @@ const Messages = { SPLIT_MAX_LEN: 'Message exceeds the max length and contains no split characters.', - BAN_RESOLVE_ID: 'Couldn\'t resolve the user ID to unban.', + BAN_RESOLVE_ID: (ban = false) => `Couldn't resolve the user ID to ${ban ? 'ban' : 'unban'}.`, PRUNE_DAYS_TYPE: 'Days must be a number', @@ -80,8 +83,18 @@ const Messages = { MESSAGE_SPLIT_MISSING: 'Message exceeds the max length and contains no split characters.', GUILD_CHANNEL_RESOLVE: 'Could not resolve channel to a guild channel.', + GUILD_OWNED: 'Guild is owned by the client.', + GUILD_RESTRICTED: (state = false) => `Guild is ${state ? 'already' : 'not'} restricted.`, + GUILD_MEMBERS_TIMEOUT: 'Members didn\'t arrive in time.', + + INVALID_TYPE: (name, expected, an = false) => `Supplied ${name} is not a${an ? 'n' : ''} ${expected}.`, + + + WEBHOOK_MESSAGE: 'The message was not sent by a webhook.', EMOJI_TYPE: 'Emoji must be a string or Emoji/ReactionEmoji', + + REACTION_RESOLVE_USER: 'Couldn\'t resolve the user ID to remove from the reaction.', }; for (const [name, message] of Object.entries(Messages)) register(name, message); diff --git a/src/structures/ClientUserSettings.js b/src/structures/ClientUserSettings.js index 33cb1d733..67466f951 100644 --- a/src/structures/ClientUserSettings.js +++ b/src/structures/ClientUserSettings.js @@ -1,5 +1,6 @@ const Constants = require('../util/Constants'); const Util = require('../util/Util'); +const { Error } = require('../errors'); /** * A wrapper around the ClientUser's settings. @@ -54,7 +55,7 @@ class ClientUserSettings { */ addRestrictedGuild(guild) { const temp = Object.assign([], this.restrictedGuilds); - if (temp.includes(guild.id)) return Promise.reject(new Error('Guild is already restricted')); + if (temp.includes(guild.id)) return Promise.reject(new Error('GUILD_RESTRICTED', true)); temp.push(guild.id); return this.update('restricted_guilds', temp).then(() => guild); } @@ -67,7 +68,7 @@ class ClientUserSettings { removeRestrictedGuild(guild) { const temp = Object.assign([], this.restrictedGuilds); const index = temp.indexOf(guild.id); - if (index < 0) return Promise.reject(new Error('Guild is not restricted')); + if (index < 0) return Promise.reject(new Error('GUILD_RESTRICTED')); temp.splice(index, 1); return this.update('restricted_guilds', temp).then(() => guild); } diff --git a/src/structures/Guild.js b/src/structures/Guild.js index 5a11de42c..991907180 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -6,6 +6,7 @@ const Invite = require('./Invite'); const GuildAuditLogs = require('./GuildAuditLogs'); const Webhook = require('./Webhook'); const { Presence } = require('./Presence'); +const GuildChannel = require('./GuildChannel'); const GuildMember = require('./GuildMember'); const VoiceRegion = require('./VoiceRegion'); const Constants = require('../util/Constants'); @@ -487,7 +488,7 @@ class Guild { */ fetchMember(user, cache = true) { user = this.client.resolver.resolveUser(user); - if (!user) return Promise.reject(new Error('User is not cached. Use Client.fetchUser first.')); + if (!user) return Promise.reject(new Error('USER_NOT_CACHED')); if (this.members.has(user.id)) return Promise.resolve(this.members.get(user.id)); return this.client.api.guilds[this.id].members[user.id].get() .then(data => { @@ -532,7 +533,7 @@ class Guild { this.client.on(Constants.Events.GUILD_MEMBERS_CHUNK, handler); this.client.setTimeout(() => { this.client.removeListener(Constants.Events.GUILD_MEMBERS_CHUNK, handler); - reject(new Error('Members didn\'t arrive in time.')); + reject(new Error('GUILD_MEMBERS_TIMEOUT')); }, 120e3); }); } @@ -730,7 +731,7 @@ class Guild { */ setPosition(position, relative) { if (this.client.user.bot) { - return Promise.reject(new Error('Setting guild position is only available for user accounts')); + return Promise.reject(new Error('FEATURE_USER_ONLY')); } return this.client.user.settings.setGuildPosition(this, position, relative); } @@ -779,7 +780,7 @@ class Guild { ban(user, options = { days: 0 }) { if (options.days) options['delete-message-days'] = options.days; const id = this.client.resolver.resolveUserID(user); - if (!id) return Promise.reject(new Error('Couldn\'t resolve the user ID to ban.')); + if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID', true)); return this.client.api.guilds[this.id].bans[id].put({ query: options }) .then(() => { if (user instanceof GuildMember) return user; @@ -996,7 +997,7 @@ class Guild { * .catch(console.error); */ leave() { - if (this.ownerID === this.client.user.id) return Promise.reject(new Error('Guild is owned by the client.')); + if (this.ownerID === this.client.user.id) return Promise.reject(new Error('GUILD_OWNED')); return this.client.api.users['@me'].guilds[this.id].delete() .then(() => this.client.actions.GuildDelete.handle({ id: this.id }).guild); } @@ -1158,11 +1159,11 @@ class Guild { setRolePosition(role, position, relative = false) { if (typeof role === 'string') { role = this.roles.get(role); - if (!role) return Promise.reject(new Error('Supplied role is not a role or snowflake.')); } + if (!(role instanceof Role)) return Promise.reject(new TypeError('INVALID_TYPE', 'role', 'Role nor a Snowflake')); position = Number(position); - if (isNaN(position)) return Promise.reject(new Error('Supplied position is not a number.')); + if (isNaN(position)) return Promise.reject(new TypeError('INVALID_TYPE', 'position', 'number')); let updatedRoles = this._sortedRoles.array(); @@ -1188,11 +1189,13 @@ class Guild { setChannelPosition(channel, position, relative = false) { if (typeof channel === 'string') { channel = this.channels.get(channel); - if (!channel) return Promise.reject(new Error('Supplied channel is not a channel or snowflake.')); + } + if (!(channel instanceof GuildChannel)) { + return Promise.reject(new TypeError('INVALID_TYPE', 'channel', 'GuildChannel nor a Snowflake')); } position = Number(position); - if (isNaN(position)) return Promise.reject(new Error('Supplied position is not a number.')); + if (isNaN(position)) return Promise.reject(new TypeError('INVALID_TYPE', 'position', 'number')); let updatedChannels = this._sortedChannels(channel.type).array(); @@ -1203,7 +1206,7 @@ class Guild { .then(() => this.client.actions.GuildChannelsPositionUpdate.handle({ guild_id: this.id, - roles: updatedChannels, + channels: updatedChannels, }).guild ); } diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index ad0d8e0d2..ff2e33a58 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -4,6 +4,7 @@ const Invite = require('./Invite'); const PermissionOverwrites = require('./PermissionOverwrites'); const Permissions = require('../util/Permissions'); const Collection = require('../util/Collection'); +const { TypeError } = require('../errors'); /** * Represents a guild channel (i.e. text channels and voice channels). @@ -163,7 +164,7 @@ class GuildChannel extends Channel { } else { userOrRole = this.client.resolver.resolveUser(userOrRole); payload.type = 'member'; - if (!userOrRole) return Promise.reject(new TypeError('Supplied parameter was neither a User nor a Role.')); + if (!userOrRole) return Promise.reject(new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role', true)); } payload.id = userOrRole.id; diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 8ffea8627..af0cd7b70 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -3,7 +3,7 @@ const Role = require('./Role'); const Permissions = require('../util/Permissions'); const Collection = require('../util/Collection'); const { Presence } = require('./Presence'); -const { Error } = require('../errors'); +const { Error, TypeError } = require('../errors'); /** * Represents a member of a guild on Discord. @@ -396,7 +396,7 @@ class GuildMember { */ addRole(role) { if (!(role instanceof Role)) role = this.guild.roles.get(role); - if (!role) return Promise.reject(new TypeError('Supplied parameter was neither a Role nor a Snowflake.')); + if (!role) return Promise.reject(new TypeError('INVALID_TYPE', 'role', 'Role nor a Snowflake')); if (this._roles.includes(role.id)) return Promise.resolve(this); return this.client.api.guilds[this.guild.id].members[this.user.id].roles[role.id] .put() @@ -426,7 +426,7 @@ class GuildMember { */ removeRole(role) { if (!(role instanceof Role)) role = this.guild.roles.get(role); - if (!role) return Promise.reject(new TypeError('Supplied parameter was neither a Role nor a Snowflake.')); + if (!role) return Promise.reject(new TypeError('INVALID_TYPE', 'role', 'Role nor a Snowflake')); return this.client.api.guilds[this.guild.id].members[this.user.id].roles[role.id] .delete() .then(() => this); diff --git a/src/structures/Message.js b/src/structures/Message.js index 4ef37ddec..2c737e5c2 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -7,7 +7,7 @@ const Util = require('../util/Util'); const Collection = require('../util/Collection'); const Constants = require('../util/Constants'); const Permissions = require('../util/Permissions'); -const { TypeError } = require('../errors'); +const { Error, TypeError } = require('../errors'); let GuildMember; /** @@ -519,7 +519,7 @@ class Message { * @returns {Promise} */ fetchWebhook() { - if (!this.webhookID) return Promise.reject(new Error('The message was not sent by a webhook.')); + if (!this.webhookID) return Promise.reject(new Error('WEBHOOK_MESSAGE')); return this.client.fetchWebhook(this.webhookID); } diff --git a/src/structures/MessageReaction.js b/src/structures/MessageReaction.js index 3ac5f4e84..ee00bbf0d 100644 --- a/src/structures/MessageReaction.js +++ b/src/structures/MessageReaction.js @@ -1,6 +1,7 @@ const Collection = require('../util/Collection'); const Emoji = require('./Emoji'); const ReactionEmoji = require('./ReactionEmoji'); +const { Error } = require('../errors'); /** * Represents a reaction to a message. @@ -62,7 +63,7 @@ class MessageReaction { */ remove(user = this.message.client.user) { const userID = this.message.client.resolver.resolveUserID(user); - if (!userID) return Promise.reject(new Error('Couldn\'t resolve the user ID to remove from the reaction.')); + if (!userID) return Promise.reject(new Error('REACTION_RESOLVE_USER')); return this.message.client.api.channels[this.message.channel.id].messages[this.message.id] .reactions[this.emoji.identifier][userID === this.message.client.user.id ? '@me' : userID] .delete() diff --git a/src/structures/User.js b/src/structures/User.js index 8550344b3..e3d2e0b4c 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -3,6 +3,7 @@ const Constants = require('../util/Constants'); const { Presence } = require('./Presence'); const UserProfile = require('./UserProfile'); const Snowflake = require('../util/Snowflake'); +const { Error } = require('../errors'); /** * Represents a user on Discord. @@ -212,7 +213,7 @@ class User { * @returns {Promise} */ deleteDM() { - if (!this.dmChannel) return Promise.reject(new Error('No DM Channel exists!')); + if (!this.dmChannel) return Promise.reject(new Error('USER_NO_DMCHANNEL')); return this.client.api.channels[this.dmChannel.id].delete() .then(data => this.client.actions.ChannelDelete.handle(data).channel); } diff --git a/src/structures/VoiceChannel.js b/src/structures/VoiceChannel.js index 617b4eee0..7de964ec6 100644 --- a/src/structures/VoiceChannel.js +++ b/src/structures/VoiceChannel.js @@ -1,5 +1,6 @@ const GuildChannel = require('./GuildChannel'); const Collection = require('../util/Collection'); +const { Error } = require('../errors'); /** * Represents a guild voice channel on Discord. @@ -113,7 +114,7 @@ class VoiceChannel extends GuildChannel { * .catch(console.error); */ join() { - if (this.client.browser) return Promise.reject(new Error('Voice connections are not available in browsers.')); + if (this.client.browser) return Promise.reject(new Error('VOICE_NO_BROWSER')); return this.client.voice.joinChannel(this); } diff --git a/src/util/Util.js b/src/util/Util.js index 121ecf4f8..2023050d0 100644 --- a/src/util/Util.js +++ b/src/util/Util.js @@ -1,7 +1,7 @@ const snekfetch = require('snekfetch'); const Constants = require('./Constants'); const ConstantsHttp = Constants.DefaultOptions.http; -const { RangeError, TypeError } = require('../errors'); +const { Error: DiscordError, RangeError, TypeError } = require('../errors'); const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k); /** @@ -58,7 +58,7 @@ class Util { */ static fetchRecommendedShards(token, guildsPerShard = 1000) { return new Promise((resolve, reject) => { - if (!token) throw new Error('TOKEN_MISSING'); + if (!token) throw new DiscordError('TOKEN_MISSING'); snekfetch.get(`${ConstantsHttp.api}/v${ConstantsHttp.version}${Constants.Endpoints.botGateway}`) .set('Authorization', `Bot ${token.replace(/^Bot\s*/i, '')}`) .end((err, res) => {