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
This commit is contained in:
SpaceEEC
2017-07-21 02:27:19 +02:00
committed by Crawl
parent 7a27b12b2b
commit 11556c0b3b
11 changed files with 49 additions and 28 deletions

View File

@@ -38,7 +38,7 @@ class ClientManager {
connectToWebSocket(token, resolve, reject) { connectToWebSocket(token, resolve, reject) {
this.client.emit(Constants.Events.DEBUG, `Authenticated using token ${token}`); this.client.emit(Constants.Events.DEBUG, `Authenticated using token ${token}`);
this.client.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 => { this.client.api.gateway.get().then(res => {
const protocolVersion = Constants.DefaultOptions.ws.version; const protocolVersion = Constants.DefaultOptions.ws.version;
const gateway = `${res.url}/?v=${protocolVersion}&encoding=${WebSocketConnection.ENCODING}`; const gateway = `${res.url}/?v=${protocolVersion}&encoding=${WebSocketConnection.ENCODING}`;

View File

@@ -13,8 +13,7 @@ const Messages = {
WS_CONNECTION_EXISTS: 'There is already an existing WebSocket connection.', WS_CONNECTION_EXISTS: 'There is already an existing WebSocket connection.',
WS_NOT_OPEN: (data = 'data') => `Websocket not open to send ${data}`, WS_NOT_OPEN: (data = 'data') => `Websocket not open to send ${data}`,
PERMISSIONS_INVALID: 'Invalid permission string or number.', PERMISSION_INVALID: 'Invalid permission string or number.',
PERMISSIONS_INVALID_FLAG: 'Invalid bitfield flag string or number',
RATELIMIT_INVALID_METHOD: 'Unknown rate limiting method.', RATELIMIT_INVALID_METHOD: 'Unknown rate limiting method.',
@@ -26,6 +25,8 @@ const Messages = {
SHARDING_IN_PROCESS: 'Shards are still being spawned', SHARDING_IN_PROCESS: 'Shards are still being spawned',
SHARDING_ALREADY_SPAWNED: count => `Already spawned ${count} shards`, 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_RANGE: 'Color must be within the range 0 - 16777215 (0xFFFFFF).',
COLOR_CONVERT: 'Unable to convert color to a number.', 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}`, FILE_NOT_FOUND: file => `File could not be found: ${file}`,
USER_STATUS: 'User status must be a string', 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_INVALID_HEARTBEAT: 'Tried to set voice heartbeat but no valid interval was specified.',
VOICE_USER_MISSING: 'Couldn\'t resolve the user to create stream.', 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_TOKEN_ABSENT: 'Token not provided from voice server packet.',
VOICE_SESSION_ABSENT: 'Session ID not supplied.', VOICE_SESSION_ABSENT: 'Session ID not supplied.',
VOICE_INVALID_ENDPOINT: 'Invalid endpoint received.', 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.', 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.', 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', 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.', 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_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', 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); for (const [name, message] of Object.entries(Messages)) register(name, message);

View File

@@ -1,5 +1,6 @@
const Constants = require('../util/Constants'); const Constants = require('../util/Constants');
const Util = require('../util/Util'); const Util = require('../util/Util');
const { Error } = require('../errors');
/** /**
* A wrapper around the ClientUser's settings. * A wrapper around the ClientUser's settings.
@@ -54,7 +55,7 @@ class ClientUserSettings {
*/ */
addRestrictedGuild(guild) { addRestrictedGuild(guild) {
const temp = Object.assign([], this.restrictedGuilds); 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); temp.push(guild.id);
return this.update('restricted_guilds', temp).then(() => guild); return this.update('restricted_guilds', temp).then(() => guild);
} }
@@ -67,7 +68,7 @@ class ClientUserSettings {
removeRestrictedGuild(guild) { removeRestrictedGuild(guild) {
const temp = Object.assign([], this.restrictedGuilds); const temp = Object.assign([], this.restrictedGuilds);
const index = temp.indexOf(guild.id); 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); temp.splice(index, 1);
return this.update('restricted_guilds', temp).then(() => guild); return this.update('restricted_guilds', temp).then(() => guild);
} }

View File

@@ -6,6 +6,7 @@ const Invite = require('./Invite');
const GuildAuditLogs = require('./GuildAuditLogs'); const GuildAuditLogs = require('./GuildAuditLogs');
const Webhook = require('./Webhook'); const Webhook = require('./Webhook');
const { Presence } = require('./Presence'); const { Presence } = require('./Presence');
const GuildChannel = require('./GuildChannel');
const GuildMember = require('./GuildMember'); const GuildMember = require('./GuildMember');
const VoiceRegion = require('./VoiceRegion'); const VoiceRegion = require('./VoiceRegion');
const Constants = require('../util/Constants'); const Constants = require('../util/Constants');
@@ -487,7 +488,7 @@ class Guild {
*/ */
fetchMember(user, cache = true) { fetchMember(user, cache = true) {
user = this.client.resolver.resolveUser(user); 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)); 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() return this.client.api.guilds[this.id].members[user.id].get()
.then(data => { .then(data => {
@@ -532,7 +533,7 @@ class Guild {
this.client.on(Constants.Events.GUILD_MEMBERS_CHUNK, handler); this.client.on(Constants.Events.GUILD_MEMBERS_CHUNK, handler);
this.client.setTimeout(() => { this.client.setTimeout(() => {
this.client.removeListener(Constants.Events.GUILD_MEMBERS_CHUNK, handler); 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); }, 120e3);
}); });
} }
@@ -730,7 +731,7 @@ class Guild {
*/ */
setPosition(position, relative) { setPosition(position, relative) {
if (this.client.user.bot) { 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); return this.client.user.settings.setGuildPosition(this, position, relative);
} }
@@ -779,7 +780,7 @@ class Guild {
ban(user, options = { days: 0 }) { ban(user, options = { days: 0 }) {
if (options.days) options['delete-message-days'] = options.days; if (options.days) options['delete-message-days'] = options.days;
const id = this.client.resolver.resolveUserID(user); 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 }) return this.client.api.guilds[this.id].bans[id].put({ query: options })
.then(() => { .then(() => {
if (user instanceof GuildMember) return user; if (user instanceof GuildMember) return user;
@@ -996,7 +997,7 @@ class Guild {
* .catch(console.error); * .catch(console.error);
*/ */
leave() { 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() return this.client.api.users['@me'].guilds[this.id].delete()
.then(() => this.client.actions.GuildDelete.handle({ id: this.id }).guild); .then(() => this.client.actions.GuildDelete.handle({ id: this.id }).guild);
} }
@@ -1158,11 +1159,11 @@ class Guild {
setRolePosition(role, position, relative = false) { setRolePosition(role, position, relative = false) {
if (typeof role === 'string') { if (typeof role === 'string') {
role = this.roles.get(role); 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); 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(); let updatedRoles = this._sortedRoles.array();
@@ -1188,11 +1189,13 @@ class Guild {
setChannelPosition(channel, position, relative = false) { setChannelPosition(channel, position, relative = false) {
if (typeof channel === 'string') { if (typeof channel === 'string') {
channel = this.channels.get(channel); 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); 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(); let updatedChannels = this._sortedChannels(channel.type).array();
@@ -1203,7 +1206,7 @@ class Guild {
.then(() => .then(() =>
this.client.actions.GuildChannelsPositionUpdate.handle({ this.client.actions.GuildChannelsPositionUpdate.handle({
guild_id: this.id, guild_id: this.id,
roles: updatedChannels, channels: updatedChannels,
}).guild }).guild
); );
} }

View File

@@ -4,6 +4,7 @@ const Invite = require('./Invite');
const PermissionOverwrites = require('./PermissionOverwrites'); const PermissionOverwrites = require('./PermissionOverwrites');
const Permissions = require('../util/Permissions'); const Permissions = require('../util/Permissions');
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const { TypeError } = require('../errors');
/** /**
* Represents a guild channel (i.e. text channels and voice channels). * Represents a guild channel (i.e. text channels and voice channels).
@@ -163,7 +164,7 @@ class GuildChannel extends Channel {
} else { } else {
userOrRole = this.client.resolver.resolveUser(userOrRole); userOrRole = this.client.resolver.resolveUser(userOrRole);
payload.type = 'member'; 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; payload.id = userOrRole.id;

View File

@@ -3,7 +3,7 @@ const Role = require('./Role');
const Permissions = require('../util/Permissions'); const Permissions = require('../util/Permissions');
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const { Presence } = require('./Presence'); const { Presence } = require('./Presence');
const { Error } = require('../errors'); const { Error, TypeError } = require('../errors');
/** /**
* Represents a member of a guild on Discord. * Represents a member of a guild on Discord.
@@ -396,7 +396,7 @@ class GuildMember {
*/ */
addRole(role) { addRole(role) {
if (!(role instanceof Role)) role = this.guild.roles.get(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); 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] return this.client.api.guilds[this.guild.id].members[this.user.id].roles[role.id]
.put() .put()
@@ -426,7 +426,7 @@ class GuildMember {
*/ */
removeRole(role) { removeRole(role) {
if (!(role instanceof Role)) role = this.guild.roles.get(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] return this.client.api.guilds[this.guild.id].members[this.user.id].roles[role.id]
.delete() .delete()
.then(() => this); .then(() => this);

View File

@@ -7,7 +7,7 @@ const Util = require('../util/Util');
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const Constants = require('../util/Constants'); const Constants = require('../util/Constants');
const Permissions = require('../util/Permissions'); const Permissions = require('../util/Permissions');
const { TypeError } = require('../errors'); const { Error, TypeError } = require('../errors');
let GuildMember; let GuildMember;
/** /**
@@ -519,7 +519,7 @@ class Message {
* @returns {Promise<?Webhook>} * @returns {Promise<?Webhook>}
*/ */
fetchWebhook() { 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); return this.client.fetchWebhook(this.webhookID);
} }

View File

@@ -1,6 +1,7 @@
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const Emoji = require('./Emoji'); const Emoji = require('./Emoji');
const ReactionEmoji = require('./ReactionEmoji'); const ReactionEmoji = require('./ReactionEmoji');
const { Error } = require('../errors');
/** /**
* Represents a reaction to a message. * Represents a reaction to a message.
@@ -62,7 +63,7 @@ class MessageReaction {
*/ */
remove(user = this.message.client.user) { remove(user = this.message.client.user) {
const userID = this.message.client.resolver.resolveUserID(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] 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] .reactions[this.emoji.identifier][userID === this.message.client.user.id ? '@me' : userID]
.delete() .delete()

View File

@@ -3,6 +3,7 @@ const Constants = require('../util/Constants');
const { Presence } = require('./Presence'); const { Presence } = require('./Presence');
const UserProfile = require('./UserProfile'); const UserProfile = require('./UserProfile');
const Snowflake = require('../util/Snowflake'); const Snowflake = require('../util/Snowflake');
const { Error } = require('../errors');
/** /**
* Represents a user on Discord. * Represents a user on Discord.
@@ -212,7 +213,7 @@ class User {
* @returns {Promise<DMChannel>} * @returns {Promise<DMChannel>}
*/ */
deleteDM() { 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() return this.client.api.channels[this.dmChannel.id].delete()
.then(data => this.client.actions.ChannelDelete.handle(data).channel); .then(data => this.client.actions.ChannelDelete.handle(data).channel);
} }

View File

@@ -1,5 +1,6 @@
const GuildChannel = require('./GuildChannel'); const GuildChannel = require('./GuildChannel');
const Collection = require('../util/Collection'); const Collection = require('../util/Collection');
const { Error } = require('../errors');
/** /**
* Represents a guild voice channel on Discord. * Represents a guild voice channel on Discord.
@@ -113,7 +114,7 @@ class VoiceChannel extends GuildChannel {
* .catch(console.error); * .catch(console.error);
*/ */
join() { 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); return this.client.voice.joinChannel(this);
} }

View File

@@ -1,7 +1,7 @@
const snekfetch = require('snekfetch'); const snekfetch = require('snekfetch');
const Constants = require('./Constants'); const Constants = require('./Constants');
const ConstantsHttp = Constants.DefaultOptions.http; 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); const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
/** /**
@@ -58,7 +58,7 @@ class Util {
*/ */
static fetchRecommendedShards(token, guildsPerShard = 1000) { static fetchRecommendedShards(token, guildsPerShard = 1000) {
return new Promise((resolve, reject) => { 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}`) snekfetch.get(`${ConstantsHttp.api}/v${ConstantsHttp.version}${Constants.Endpoints.botGateway}`)
.set('Authorization', `Bot ${token.replace(/^Bot\s*/i, '')}`) .set('Authorization', `Bot ${token.replace(/^Bot\s*/i, '')}`)
.end((err, res) => { .end((err, res) => {