From ab7f9e80b4b6f86ed8bf2ad56585188b3388dd36 Mon Sep 17 00:00:00 2001 From: Ryan Munro Date: Sun, 26 Jan 2020 01:36:35 +1100 Subject: [PATCH] feat(MessageReaction): backport removeAll and MessageReactionRemoveEmoji event (#3741) * Add new action and websocket handler * Add REST method for removing reaction emoji * Update Message#_removeReaction to handle removing whole emoji * Add MessageReaction#removeAll and update typings * Apply uncached user fix --- src/client/actions/ActionsManager.js | 1 + .../actions/MessageReactionRemoveEmoji.js | 27 +++++++++++++++++++ src/client/rest/RESTMethods.js | 11 ++++++++ .../packets/WebSocketPacketManager.js | 1 + .../handlers/MessageReactionRemoveEmoji.js | 11 ++++++++ src/structures/Message.js | 4 +++ src/structures/MessageReaction.js | 11 ++++++++ src/util/Constants.js | 3 +++ typings/index.d.ts | 3 +++ 9 files changed, 72 insertions(+) create mode 100644 src/client/actions/MessageReactionRemoveEmoji.js create mode 100644 src/client/websocket/packets/handlers/MessageReactionRemoveEmoji.js diff --git a/src/client/actions/ActionsManager.js b/src/client/actions/ActionsManager.js index 2bc466c1f..f9739cc6c 100644 --- a/src/client/actions/ActionsManager.js +++ b/src/client/actions/ActionsManager.js @@ -8,6 +8,7 @@ class ActionsManager { this.register(require('./MessageUpdate')); this.register(require('./MessageReactionAdd')); this.register(require('./MessageReactionRemove')); + this.register(require('./MessageReactionRemoveEmoji')); this.register(require('./MessageReactionRemoveAll')); this.register(require('./ChannelCreate')); this.register(require('./ChannelDelete')); diff --git a/src/client/actions/MessageReactionRemoveEmoji.js b/src/client/actions/MessageReactionRemoveEmoji.js new file mode 100644 index 000000000..12b444596 --- /dev/null +++ b/src/client/actions/MessageReactionRemoveEmoji.js @@ -0,0 +1,27 @@ +const Action = require('./Action'); +const Constants = require('../../util/Constants'); + +class MessageReactionRemoveEmoji extends Action { + handle(data) { + // Verify channel + const channel = this.client.channels.get(data.channel_id); + if (!channel || channel.type === 'voice') return false; + // Verify message + const message = channel.messages.get(data.message_id); + if (!message) return false; + if (!data.emoji) return false; + // Verify reaction + const reaction = message._removeReaction(data.emoji); + if (reaction) this.client.emit(Constants.Events.MESSAGE_REACTION_REMOVE_EMOJI, reaction); + + return { message, reaction }; + } +} + +/** + * Emitted whenever a reaction emoji is removed from a cached message. + * @event Client#messageReactionRemoveEmoji + * @param {MessageReaction} messageReaction The reaction object + */ + +module.exports = MessageReactionRemoveEmoji; diff --git a/src/client/rest/RESTMethods.js b/src/client/rest/RESTMethods.js index 92d4ecb3a..42e15f9f4 100644 --- a/src/client/rest/RESTMethods.js +++ b/src/client/rest/RESTMethods.js @@ -945,6 +945,17 @@ class RESTMethods { ); } + removeMessageReactionEmoji(message, emoji) { + const endpoint = Endpoints.Message(message).Reaction(emoji); + return this.rest.makeRequest('delete', endpoint, true).then(() => + this.client.actions.MessageReactionRemoveEmoji.handle({ + message_id: message.id, + emoji: Util.parseEmoji(emoji), + channel_id: message.channel.id, + }).reaction + ); + } + removeMessageReactions(message) { return this.rest.makeRequest('delete', Endpoints.Message(message).reactions, true) .then(() => message); diff --git a/src/client/websocket/packets/WebSocketPacketManager.js b/src/client/websocket/packets/WebSocketPacketManager.js index 5ad417b06..28d78d8c7 100644 --- a/src/client/websocket/packets/WebSocketPacketManager.js +++ b/src/client/websocket/packets/WebSocketPacketManager.js @@ -55,6 +55,7 @@ class WebSocketPacketManager { this.register(Constants.WSEvents.RELATIONSHIP_REMOVE, require('./handlers/RelationshipRemove')); this.register(Constants.WSEvents.MESSAGE_REACTION_ADD, require('./handlers/MessageReactionAdd')); this.register(Constants.WSEvents.MESSAGE_REACTION_REMOVE, require('./handlers/MessageReactionRemove')); + this.register(Constants.WSEvents.MESSAGE_REACTION_REMOVE, require('./handlers/MessageReactionRemoveEmoji')); this.register(Constants.WSEvents.MESSAGE_REACTION_REMOVE_ALL, require('./handlers/MessageReactionRemoveAll')); this.register(Constants.WSEvents.WEBHOOKS_UPDATE, require('./handlers/WebhooksUpdate')); } diff --git a/src/client/websocket/packets/handlers/MessageReactionRemoveEmoji.js b/src/client/websocket/packets/handlers/MessageReactionRemoveEmoji.js new file mode 100644 index 000000000..c16af7479 --- /dev/null +++ b/src/client/websocket/packets/handlers/MessageReactionRemoveEmoji.js @@ -0,0 +1,11 @@ +const AbstractHandler = require('./AbstractHandler'); + +class MessageReactionRemoveEmoji extends AbstractHandler { + handle(packet) { + const client = this.packetManager.client; + const data = packet.d; + client.actions.MessageReactionRemoveEmoji.handle(data); + } +} + +module.exports = MessageReactionRemoveEmoji; diff --git a/src/structures/Message.js b/src/structures/Message.js index 044b3f5a3..10eafe650 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -590,6 +590,10 @@ class Message { const emojiID = emoji.id ? `${emoji.name}:${emoji.id}` : emoji.name; if (this.reactions.has(emojiID)) { const reaction = this.reactions.get(emojiID); + if (!user) { + this.reactions.delete(emojiID); + return reaction; + } if (reaction.users.has(user.id)) { reaction.users.delete(user.id); reaction.count--; diff --git a/src/structures/MessageReaction.js b/src/structures/MessageReaction.js index 6e21b6a29..9109e18c1 100644 --- a/src/structures/MessageReaction.js +++ b/src/structures/MessageReaction.js @@ -69,6 +69,17 @@ class MessageReaction { ); } + /** + * Removes this reaction from the message + * @returns {Promise} + */ + removeAll() { + const message = this.message; + return message.client.rest.methods.removeMessageReactionEmoji( + message, this.emoji.identifier + ); + } + /** * Fetch all the users that gave this reaction. Resolves with a collection of users, mapped by their IDs. * @param {number} [limit=100] The maximum amount of users to fetch, defaults to 100 diff --git a/src/util/Constants.js b/src/util/Constants.js index 3b841c53f..f6039526b 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -349,6 +349,7 @@ exports.Events = { MESSAGE_BULK_DELETE: 'messageDeleteBulk', MESSAGE_REACTION_ADD: 'messageReactionAdd', MESSAGE_REACTION_REMOVE: 'messageReactionRemove', + MESSAGE_REACTION_REMOVE_EMOJI: 'messageReactionRemoveEmoji', MESSAGE_REACTION_REMOVE_ALL: 'messageReactionRemoveAll', USER_UPDATE: 'userUpdate', USER_NOTE_UPDATE: 'userNoteUpdate', @@ -418,6 +419,7 @@ exports.ActivityFlags = { * * MESSAGE_DELETE_BULK * * MESSAGE_REACTION_ADD * * MESSAGE_REACTION_REMOVE + * * MESSAGE_REACTION_REMOVE_EMOJI * * MESSAGE_REACTION_REMOVE_ALL * * USER_UPDATE * * USER_NOTE_UPDATE @@ -461,6 +463,7 @@ exports.WSEvents = { MESSAGE_DELETE_BULK: 'MESSAGE_DELETE_BULK', MESSAGE_REACTION_ADD: 'MESSAGE_REACTION_ADD', MESSAGE_REACTION_REMOVE: 'MESSAGE_REACTION_REMOVE', + MESSAGE_REACTION_RMEOVE_EMOJI: 'MESSAGE_REACTION_REMOVE_EMOJI', MESSAGE_REACTION_REMOVE_ALL: 'MESSAGE_REACTION_REMOVE_ALL', USER_UPDATE: 'USER_UPDATE', USER_NOTE_UPDATE: 'USER_NOTE_UPDATE', diff --git a/typings/index.d.ts b/typings/index.d.ts index 6bc16c347..6e7a85b52 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -138,6 +138,7 @@ declare module 'discord.js' { public on(event: 'messageDeleteBulk', listener: (messages: Collection) => void): this; public on(event: 'messageReactionAdd', listener: (messageReaction: MessageReaction, user: User) => void): this; public on(event: 'messageReactionRemove', listener: (messageReaction: MessageReaction, user: User) => void): this; + public on(event: 'messageReactionRemoveEmoji', listener: (messageReaction: MessageReaction) => void): this; public on(event: 'messageReactionRemoveAll', listener: (message: Message) => void): this; public on(event: 'messageUpdate', listener: (oldMessage: Message, newMessage: Message) => void): this; public on(event: 'presenceUpdate', listener: (oldMember: GuildMember, newMember: GuildMember) => void): this; @@ -187,6 +188,7 @@ declare module 'discord.js' { public once(event: 'messageDeleteBulk', listener: (messages: Collection) => void): this; public once(event: 'messageReactionAdd', listener: (messageReaction: MessageReaction, user: User) => void): this; public once(event: 'messageReactionRemove', listener: (messageReaction: MessageReaction, user: User) => void): this; + public once(event: 'messageReactionRemoveEmoji', listener: (messageReaction: MessageReaction) => void): this; public once(event: 'messageReactionRemoveAll', listener: (message: Message) => void): this; public once(event: 'messageUpdate', listener: (oldMessage: Message, newMessage: Message) => void): this; public once(event: 'presenceUpdate', listener: (oldMember: GuildMember, newMember: GuildMember) => void): this; @@ -919,6 +921,7 @@ declare module 'discord.js' { public users: Collection; public fetchUsers(limit?: number, options?: { after?: number; before?: number }): Promise>; public remove(user?: UserResolvable): Promise; + public removeAll(): Promise; } export class NewsChannel extends TextChannel {