diff --git a/src/client/rest/RESTMethods.js b/src/client/rest/RESTMethods.js
index 023a50a1b..14a28ee5e 100644
--- a/src/client/rest/RESTMethods.js
+++ b/src/client/rest/RESTMethods.js
@@ -878,7 +878,8 @@ class RESTMethods {
}
resetApplication(id) {
- return this.rest.makeRequest('post', Endpoints.OAUTH2.Application(id).reset, true)
+ return this.rest.makeRequest('post', Endpoints.OAUTH2.Application(id).resetToken, true)
+ .then(() => this.rest.makeRequest('post', Endpoints.OAUTH2.Application(id).resetSecret, true))
.then(app => new OAuth2Application(this.client, app));
}
@@ -908,6 +909,10 @@ class RESTMethods {
patchUserSettings(data) {
return this.rest.makeRequest('patch', Constants.Endpoints.User('@me').settings, true, data);
}
+
+ patchClientUserGuildSettings(guildID, data) {
+ return this.rest.makeRequest('patch', Constants.Endpoints.User('@me').Guild(guildID).settings, true, data);
+ }
}
module.exports = RESTMethods;
diff --git a/src/client/rest/RequestHandlers/Burst.js b/src/client/rest/RequestHandlers/Burst.js
index e5a160246..f3311ab65 100644
--- a/src/client/rest/RequestHandlers/Burst.js
+++ b/src/client/rest/RequestHandlers/Burst.js
@@ -40,6 +40,12 @@ class BurstRequestHandler extends RequestHandler {
this.handle();
this.resetTimeout = null;
}, Number(res.headers['retry-after']) + this.client.options.restTimeOffset);
+ } else if (err.status >= 500 && err.status < 600) {
+ this.queue.unshift(item);
+ this.resetTimeout = this.client.setTimeout(() => {
+ this.handle();
+ this.resetTimeout = null;
+ }, 1e3 + this.client.options.restTimeOffset);
} else {
item.reject(err.status === 400 ? new DiscordAPIError(res.body) : err);
this.handle();
diff --git a/src/client/rest/RequestHandlers/Sequential.js b/src/client/rest/RequestHandlers/Sequential.js
index 04f805237..42b07452e 100644
--- a/src/client/rest/RequestHandlers/Sequential.js
+++ b/src/client/rest/RequestHandlers/Sequential.js
@@ -64,6 +64,9 @@ class SequentialRequestHandler extends RequestHandler {
resolve();
}, Number(res.headers['retry-after']) + this.restManager.client.options.restTimeOffset);
if (res.headers['x-ratelimit-global']) this.globalLimit = true;
+ } else if (err.status >= 500 && err.status < 600) {
+ this.queue.unshift(item);
+ this.restManager.client.setTimeout(resolve, 1e3 + this.client.options.restTimeOffset);
} else {
item.reject(err.status >= 400 && err.status < 500 ? new DiscordAPIError(res.body) : err);
resolve(err);
diff --git a/src/client/websocket/packets/WebSocketPacketManager.js b/src/client/websocket/packets/WebSocketPacketManager.js
index 079ef5d8c..efc42df4a 100644
--- a/src/client/websocket/packets/WebSocketPacketManager.js
+++ b/src/client/websocket/packets/WebSocketPacketManager.js
@@ -39,6 +39,7 @@ class WebSocketPacketManager {
this.register(Constants.WSEvents.USER_UPDATE, require('./handlers/UserUpdate'));
this.register(Constants.WSEvents.USER_NOTE_UPDATE, require('./handlers/UserNoteUpdate'));
this.register(Constants.WSEvents.USER_SETTINGS_UPDATE, require('./handlers/UserSettingsUpdate'));
+ this.register(Constants.WSEvents.USER_GUILD_SETTINGS_UPDATE, require('./handlers/UserGuildSettingsUpdate'));
this.register(Constants.WSEvents.VOICE_STATE_UPDATE, require('./handlers/VoiceStateUpdate'));
this.register(Constants.WSEvents.TYPING_START, require('./handlers/TypingStart'));
this.register(Constants.WSEvents.MESSAGE_CREATE, require('./handlers/MessageCreate'));
diff --git a/src/client/websocket/packets/handlers/Ready.js b/src/client/websocket/packets/handlers/Ready.js
index d7ee8ed11..8c2492abf 100644
--- a/src/client/websocket/packets/handlers/Ready.js
+++ b/src/client/websocket/packets/handlers/Ready.js
@@ -10,6 +10,7 @@ class ReadyHandler extends AbstractHandler {
client.ws.heartbeat();
data.user.user_settings = data.user_settings;
+ data.user.user_guild_settings = data.user_guild_settings;
const clientUser = new ClientUser(client, data.user);
client.user = clientUser;
diff --git a/src/client/websocket/packets/handlers/UserGuildSettingsUpdate.js b/src/client/websocket/packets/handlers/UserGuildSettingsUpdate.js
new file mode 100644
index 000000000..1470a3c84
--- /dev/null
+++ b/src/client/websocket/packets/handlers/UserGuildSettingsUpdate.js
@@ -0,0 +1,18 @@
+const AbstractHandler = require('./AbstractHandler');
+const Constants = require('../../../../util/Constants');
+
+class UserGuildSettingsUpdateHandler extends AbstractHandler {
+ handle(packet) {
+ const client = this.packetManager.client;
+ client.user.guildSettings.get(packet.d.guild_id).patch(packet.d);
+ client.emit(Constants.Events.USER_GUILD_SETTINGS_UPDATE, client.user.guildSettings.get(packet.d.guild_id));
+ }
+}
+
+/**
+ * Emitted whenever the client user's settings update.
+ * @event Client#clientUserGuildSettingsUpdate
+ * @param {ClientUserGuildSettings} clientUserGuildSettings The new client user guild settings
+ */
+
+module.exports = UserGuildSettingsUpdateHandler;
diff --git a/src/structures/ClientUser.js b/src/structures/ClientUser.js
index e6171ebec..a612e1a2e 100644
--- a/src/structures/ClientUser.js
+++ b/src/structures/ClientUser.js
@@ -1,6 +1,7 @@
const User = require('./User');
const Collection = require('../util/Collection');
const ClientUserSettings = require('./ClientUserSettings');
+const ClientUserGuildSettings = require('./ClientUserGuildSettings');
const Constants = require('../util/Constants');
/**
@@ -73,6 +74,18 @@ class ClientUser extends User {
* @type {?ClientUserSettings}
*/
this.settings = data.user_settings ? new ClientUserSettings(this, data.user_settings) : null;
+
+ /**
+ * All of the user's guild settings
+ * This is only filled when using a user account
+ * @type {Collection}
+ */
+ this.guildSettings = new Collection();
+ if (data.user_guild_settings) {
+ for (const settings of data.user_guild_settings) {
+ this.guildSettings.set(settings.guild_id, new ClientUserGuildSettings(settings, this.client));
+ }
+ }
}
edit(data) {
diff --git a/src/structures/ClientUserChannelOverride.js b/src/structures/ClientUserChannelOverride.js
new file mode 100644
index 000000000..12790b9ac
--- /dev/null
+++ b/src/structures/ClientUserChannelOverride.js
@@ -0,0 +1,28 @@
+const Constants = require('../util/Constants');
+
+/**
+ * A wrapper around the ClientUser's channel overrides.
+ */
+class ClientUserChannelOverride {
+ constructor(data) {
+ this.patch(data);
+ }
+
+ /**
+ * Patch the data contained in this class with new partial data.
+ * @param {Object} data Data to patch this with
+ */
+ patch(data) {
+ for (const key of Object.keys(Constants.UserChannelOverrideMap)) {
+ const value = Constants.UserChannelOverrideMap[key];
+ if (!data.hasOwnProperty(key)) continue;
+ if (typeof value === 'function') {
+ this[value.name] = value(data[key]);
+ } else {
+ this[value] = data[key];
+ }
+ }
+ }
+}
+
+module.exports = ClientUserChannelOverride;
diff --git a/src/structures/ClientUserGuildSettings.js b/src/structures/ClientUserGuildSettings.js
new file mode 100644
index 000000000..146be9872
--- /dev/null
+++ b/src/structures/ClientUserGuildSettings.js
@@ -0,0 +1,58 @@
+const Constants = require('../util/Constants');
+const Collection = require('../util/Collection');
+const ClientUserChannelOverride = require('./ClientUserChannelOverride');
+
+/**
+ * A wrapper around the ClientUser's guild settings.
+ */
+class ClientUserGuildSettings {
+ constructor(data, client) {
+ /**
+ * The client that created the instance of the ClientUserGuildSettings
+ * @name ClientUserGuildSettings#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: client });
+ /**
+ * The ID of the guild this settings are for
+ * @type {Snowflake}
+ */
+ this.guildID = data.guild_id;
+ this.channelOverrides = new Collection();
+ this.patch(data);
+ }
+
+ /**
+ * Patch the data contained in this class with new partial data.
+ * @param {Object} data Data to patch this with
+ */
+ patch(data) {
+ for (const key of Object.keys(Constants.UserGuildSettingsMap)) {
+ const value = Constants.UserGuildSettingsMap[key];
+ if (!data.hasOwnProperty(key)) continue;
+ if (key === 'channel_overrides') {
+ for (const channel of data[key]) {
+ this.channelOverrides.set(channel.channel_id,
+ new ClientUserChannelOverride(channel));
+ }
+ } else if (typeof value === 'function') {
+ this[value.name] = value(data[key]);
+ } else {
+ this[value] = data[key];
+ }
+ }
+ }
+
+ /**
+ * Update a specific property of the guild settings.
+ * @param {string} name Name of property
+ * @param {value} value Value to patch
+ * @returns {Promise