From 6dc95cd0846b8e473d6b3b8dac9f8a74e2225c9a Mon Sep 17 00:00:00 2001 From: Programmix Date: Sun, 30 Oct 2016 20:06:09 -0700 Subject: [PATCH] Add support for notes (#860) * Add support for notes * Ensure consistency with notes from ready payload * Add getter method for users * Minor tweaks * Update warning messages * More minor fixes --- src/client/actions/ActionsManager.js | 1 + src/client/actions/UserNoteUpdate.js | 30 +++++++++++++++++++ src/client/rest/RESTMethods.js | 5 ++++ .../packets/WebSocketPacketManager.js | 1 + .../websocket/packets/handlers/Ready.js | 9 ++++++ .../packets/handlers/UserNoteUpdate.js | 12 ++++++++ src/structures/ClientUser.js | 7 +++++ src/structures/User.js | 24 +++++++++++++++ src/util/Constants.js | 3 ++ 9 files changed, 92 insertions(+) create mode 100644 src/client/actions/UserNoteUpdate.js create mode 100644 src/client/websocket/packets/handlers/UserNoteUpdate.js diff --git a/src/client/actions/ActionsManager.js b/src/client/actions/ActionsManager.js index dbfdc19dd..e4545fd73 100644 --- a/src/client/actions/ActionsManager.js +++ b/src/client/actions/ActionsManager.js @@ -21,6 +21,7 @@ class ActionsManager { this.register('GuildRoleUpdate'); this.register('UserGet'); this.register('UserUpdate'); + this.register('UserNoteUpdate'); this.register('GuildSync'); this.register('GuildEmojiCreate'); this.register('GuildEmojiDelete'); diff --git a/src/client/actions/UserNoteUpdate.js b/src/client/actions/UserNoteUpdate.js new file mode 100644 index 000000000..4c2cc2187 --- /dev/null +++ b/src/client/actions/UserNoteUpdate.js @@ -0,0 +1,30 @@ +const Action = require('./Action'); +const Constants = require('../../util/Constants'); + +class UserNoteUpdateAction extends Action { + handle(data) { + const client = this.client; + + const oldNote = client.user.notes.get(data.id); + const note = data.note.length ? data.note : null; + + client.user.notes.set(data.id, note); + + client.emit(Constants.Events.USER_NOTE_UPDATE, data.id, oldNote, note); + + return { + old: oldNote, + updated: note, + }; + } +} + +/** + * Emitted whenever a note is updated. + * @event Client#userNoteUpdate + * @param {User} user The user the note belongs to + * @param {string} oldNote The note content before the update + * @param {string} newNote The note content after the update + */ + +module.exports = UserNoteUpdateAction; diff --git a/src/client/rest/RESTMethods.js b/src/client/rest/RESTMethods.js index 52ec23205..0c86c6db5 100644 --- a/src/client/rest/RESTMethods.js +++ b/src/client/rest/RESTMethods.js @@ -616,6 +616,11 @@ class RESTMethods { new ClientOAuth2Application(this.rest.client, app) ); } + + setNote(user, note) { + return this.rest.makeRequest('put', Constants.Endpoints.note(user.id), true, { note }) + .then(() => user); + } } module.exports = RESTMethods; diff --git a/src/client/websocket/packets/WebSocketPacketManager.js b/src/client/websocket/packets/WebSocketPacketManager.js index 99ae348b7..ecff0eec4 100644 --- a/src/client/websocket/packets/WebSocketPacketManager.js +++ b/src/client/websocket/packets/WebSocketPacketManager.js @@ -33,6 +33,7 @@ class WebSocketPacketManager { this.register(Constants.WSEvents.CHANNEL_UPDATE, 'ChannelUpdate'); this.register(Constants.WSEvents.PRESENCE_UPDATE, 'PresenceUpdate'); this.register(Constants.WSEvents.USER_UPDATE, 'UserUpdate'); + this.register(Constants.WSEvents.USER_NOTE_UPDATE, 'UserNoteUpdate'); this.register(Constants.WSEvents.VOICE_STATE_UPDATE, 'VoiceStateUpdate'); this.register(Constants.WSEvents.TYPING_START, 'TypingStart'); this.register(Constants.WSEvents.MESSAGE_CREATE, 'MessageCreate'); diff --git a/src/client/websocket/packets/handlers/Ready.js b/src/client/websocket/packets/handlers/Ready.js index bb35ea47b..96d8557d7 100644 --- a/src/client/websocket/packets/handlers/Ready.js +++ b/src/client/websocket/packets/handlers/Ready.js @@ -31,6 +31,15 @@ class ReadyHandler extends AbstractHandler { client._setPresence(presence.user.id, presence); } + if (data.notes) { + for (const user in data.notes) { + let note = data.notes[user]; + if (!note.length) note = null; + + client.user.notes.set(user, note); + } + } + if (!client.user.bot && client.options.sync) client.setInterval(client.syncGuilds.bind(client), 30000); client.once('ready', client.syncGuilds.bind(client)); diff --git a/src/client/websocket/packets/handlers/UserNoteUpdate.js b/src/client/websocket/packets/handlers/UserNoteUpdate.js new file mode 100644 index 000000000..1e4777a39 --- /dev/null +++ b/src/client/websocket/packets/handlers/UserNoteUpdate.js @@ -0,0 +1,12 @@ +const AbstractHandler = require('./AbstractHandler'); + +class UserNoteUpdateHandler extends AbstractHandler { + handle(packet) { + const client = this.packetManager.client; + const data = packet.d; + + client.actions.UserNoteUpdate.handle(data); + } +} + +module.exports = UserNoteUpdateHandler; diff --git a/src/structures/ClientUser.js b/src/structures/ClientUser.js index 1a2e6466b..69e128581 100644 --- a/src/structures/ClientUser.js +++ b/src/structures/ClientUser.js @@ -36,6 +36,13 @@ class ClientUser extends User { * @type {Collection} */ this.blocked = new Collection(); + + /** + * A Collection of notes for the logged in user. + * This is only filled for user accounts, not bot accounts. + * @type {Collection} + */ + this.notes = new Collection(); } edit(data) { diff --git a/src/structures/User.js b/src/structures/User.js index b9ac5b522..3dcd9da79 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -97,6 +97,16 @@ class User { return Constants.Endpoints.avatar(this.id, this.avatar); } + /** + * The note that is set for the user + * This is only available for user accounts. + * @type {?string} + * @readonly + */ + get note() { + return this.client.user.notes.get(this.id) || null; + } + /** * Check whether the user is typing in a channel. * @param {ChannelResolvable} channel The channel to check in @@ -137,6 +147,7 @@ class User { /** * Sends a friend request to the user + * This is only available for user accounts. * @returns {Promise} */ addFriend() { @@ -145,6 +156,7 @@ class User { /** * Removes the user from your friends + * This is only available for user accounts. * @returns {Promise} */ removeFriend() { @@ -153,6 +165,7 @@ class User { /** * Blocks the user + * This is only available for user accounts. * @returns {Promise} */ block() { @@ -161,6 +174,7 @@ class User { /** * Unblocks the user + * This is only available for user accounts. * @returns {Promise} */ unblock() { @@ -175,6 +189,16 @@ class User { return this.client.rest.methods.fetchUserProfile(this); } + /** + * Sets a note for the user + * This is only available for user accounts. + * @param {string} note The note to set for the user + * @returns {Promise} + */ + setNote(note) { + return this.client.rest.methods.setNote(this, note); + } + /** * Checks if the user is equal to another. It compares username, ID, discriminator, status and the game being played. * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties. diff --git a/src/util/Constants.js b/src/util/Constants.js index f21141b82..3fa18b869 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -88,6 +88,7 @@ const Endpoints = exports.Endpoints = { me: `${API}/users/@me`, meGuild: (guildID) => `${Endpoints.me}/guilds/${guildID}`, relationships: (userID) => `${Endpoints.user(userID)}/relationships`, + note: (userID) => `${Endpoints.me}/notes/${userID}`, // guilds guilds: `${API}/guilds`, @@ -206,6 +207,7 @@ exports.Events = { MESSAGE_REACTION_ADD: 'messageReactionAdd', MESSAGE_REACTION_REMOVE: 'messageReactionRemove', USER_UPDATE: 'userUpdate', + USER_NOTE_UPDATE: 'userNoteUpdate', PRESENCE_UPDATE: 'presenceUpdate', VOICE_STATE_UPDATE: 'voiceStateUpdate', TYPING_START: 'typingStart', @@ -243,6 +245,7 @@ exports.WSEvents = { MESSAGE_REACTION_ADD: 'MESSAGE_REACTION_ADD', MESSAGE_REACTION_REMOVE: 'MESSAGE_REACTION_REMOVE', USER_UPDATE: 'USER_UPDATE', + USER_NOTE_UPDATE: 'USER_NOTE_UPDATE', PRESENCE_UPDATE: 'PRESENCE_UPDATE', VOICE_STATE_UPDATE: 'VOICE_STATE_UPDATE', TYPING_START: 'TYPING_START',