diff --git a/d2m/actions/remove-reaction.js b/d2m/actions/remove-reaction.js index b2dba0f..95fc0aa 100644 --- a/d2m/actions/remove-reaction.js +++ b/d2m/actions/remove-reaction.js @@ -23,14 +23,22 @@ async function removeSomeReactions(data) { const eventIDForMessage = select("event_message", "event_id", {message_id: data.message_id, reaction_part: 0}).pluck().get() if (!eventIDForMessage) return - /** @type {Ty.Pagination>} */ - const relations = await api.getRelations(roomID, eventIDForMessage, "m.annotation") + /** @type {Ty.Event.Outer[]} */ + let reactions = [] + /** @type {string | undefined} */ + let nextBatch = undefined + do { + /** @type {Ty.Pagination>} */ + const res = await api.getRelations(roomID, eventIDForMessage, {from: nextBatch}, "m.annotation") + reactions = reactions.concat(res.chunk) + nextBatch = res.next_batch + } while (nextBatch) // Run the proper strategy and any strategy-specific database changes const removals = await - ( "user_id" in data ? removeReaction(data, relations) - : "emoji" in data ? removeEmojiReaction(data, relations) - : removeAllReactions(data, relations)) + ( "user_id" in data ? removeReaction(data, reactions) + : "emoji" in data ? removeEmojiReaction(data, reactions) + : removeAllReactions(data, reactions)) // Redact the events and delete individual stored events in the database for (const removal of removals) { @@ -41,33 +49,33 @@ async function removeSomeReactions(data) { /** * @param {DiscordTypes.GatewayMessageReactionRemoveDispatchData} data - * @param {Ty.Pagination>} relations + * @param {Ty.Event.Outer[]} reactions */ -async function removeReaction(data, relations) { +async function removeReaction(data, reactions) { const key = await emojiToKey.emojiToKey(data.emoji) - return converter.removeReaction(data, relations, key) + return converter.removeReaction(data, reactions, key) } /** * @param {DiscordTypes.GatewayMessageReactionRemoveEmojiDispatchData} data - * @param {Ty.Pagination>} relations + * @param {Ty.Event.Outer[]} reactions */ -async function removeEmojiReaction(data, relations) { +async function removeEmojiReaction(data, reactions) { const key = await emojiToKey.emojiToKey(data.emoji) const discordPreferredEncoding = emoji.encodeEmoji(key, undefined) db.prepare("DELETE FROM reaction WHERE message_id = ? AND encoded_emoji = ?").run(data.message_id, discordPreferredEncoding) - return converter.removeEmojiReaction(data, relations, key) + return converter.removeEmojiReaction(data, reactions, key) } /** * @param {DiscordTypes.GatewayMessageReactionRemoveAllDispatchData} data - * @param {Ty.Pagination>} relations + * @param {Ty.Event.Outer[]} reactions */ -async function removeAllReactions(data, relations) { +async function removeAllReactions(data, reactions) { db.prepare("DELETE FROM reaction WHERE message_id = ?").run(data.message_id) - return converter.removeAllReactions(data, relations) + return converter.removeAllReactions(data, reactions) } module.exports.removeSomeReactions = removeSomeReactions diff --git a/d2m/converters/remove-reaction.js b/d2m/converters/remove-reaction.js index 4fed269..a6c8ace 100644 --- a/d2m/converters/remove-reaction.js +++ b/d2m/converters/remove-reaction.js @@ -17,15 +17,15 @@ const utils = sync.require("../../m2d/converters/utils") /** * @param {DiscordTypes.GatewayMessageReactionRemoveDispatchData} data - * @param {Ty.Pagination>} relations + * @param {Ty.Event.Outer[]} reactions * @param {string} key */ -function removeReaction(data, relations, key) { +function removeReaction(data, reactions, key) { /** @type {ReactionRemoveRequest[]} */ const removals = [] const wantToRemoveMatrixReaction = data.user_id === discord.application.id - for (const event of relations.chunk) { + for (const event of reactions) { const eventID = event.event_id if (event.content["m.relates_to"].key === key) { const lookingAtMatrixReaction = !utils.eventSenderIsFromDiscord(event.sender) @@ -52,14 +52,14 @@ function removeReaction(data, relations, key) { /** * @param {DiscordTypes.GatewayMessageReactionRemoveEmojiDispatchData} data - * @param {Ty.Pagination>} relations + * @param {Ty.Event.Outer[]} relations * @param {string} key */ function removeEmojiReaction(data, relations, key) { /** @type {ReactionRemoveRequest[]} */ const removals = [] - for (const event of relations.chunk) { + for (const event of relations) { const eventID = event.event_id if (event.content["m.relates_to"].key === key) { const mxid = utils.eventSenderIsFromDiscord(event.sender) ? event.sender : null @@ -72,11 +72,11 @@ function removeEmojiReaction(data, relations, key) { /** * @param {DiscordTypes.GatewayMessageReactionRemoveAllDispatchData} data - * @param {Ty.Pagination>} relations + * @param {Ty.Event.Outer[]} relations * @returns {ReactionRemoveRequest[]} */ function removeAllReactions(data, relations) { - return relations.chunk.map(event => { + return relations.map(event => { const eventID = event.event_id const mxid = utils.eventSenderIsFromDiscord(event.sender) ? event.sender : null return {eventID, mxid} diff --git a/d2m/converters/remove-reaction.test.js b/d2m/converters/remove-reaction.test.js index a63721f..dc6eda5 100644 --- a/d2m/converters/remove-reaction.test.js +++ b/d2m/converters/remove-reaction.test.js @@ -29,30 +29,28 @@ function fakeAllReactionRemoval() { } } -function fakeChunk(chunk) { - return { - chunk: chunk.map(({sender, key}, i) => ({ - content: { - "m.relates_to": { - rel_type: "m.annotation", - event_id: "$message", - key - } - }, - event_id: `$reaction_${i}`, - sender, - type: "m.reaction", - origin_server_ts: 0, - room_id: "!THE_ROOM", - unsigned: null - })) - } +function fakeReactions(reactions) { + return reactions.map(({sender, key}, i) => ({ + content: { + "m.relates_to": { + rel_type: "m.annotation", + event_id: "$message", + key + } + }, + event_id: `$reaction_${i}`, + sender, + type: "m.reaction", + origin_server_ts: 0, + room_id: "!THE_ROOM", + unsigned: null + })) } test("remove reaction: a specific discord user's reaction is removed", t => { const removals = removeReaction.removeReaction( fakeSpecificReactionRemoval("820865262526005258", "🐈", null), - fakeChunk([{key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}]), + fakeReactions([{key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}]), "🐈" ) t.deepEqual(removals, [{ @@ -64,7 +62,7 @@ test("remove reaction: a specific discord user's reaction is removed", t => { test("remove reaction: a specific matrix user's reaction is removed", t => { const removals = removeReaction.removeReaction( fakeSpecificReactionRemoval(BRIDGE_ID, "🐈", null), - fakeChunk([{key: "🐈", sender: "@cadence:cadence.moe"}]), + fakeReactions([{key: "🐈", sender: "@cadence:cadence.moe"}]), "🐈" ) t.deepEqual(removals, [{ @@ -77,7 +75,7 @@ test("remove reaction: a specific matrix user's reaction is removed", t => { test("remove reaction: a specific discord user's reaction is removed when there are multiple reactions", t => { const removals = removeReaction.removeReaction( fakeSpecificReactionRemoval("820865262526005258", "🐈", null), - fakeChunk([ + fakeReactions([ {key: "🐈‍⬛", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈", sender: "@_ooye_extremity:cadence.moe"}, @@ -95,7 +93,7 @@ test("remove reaction: a specific discord user's reaction is removed when there test("remove reaction: a specific reaction leads to all matrix users' reaction of the emoji being removed", t => { const removals = removeReaction.removeReaction( fakeSpecificReactionRemoval(BRIDGE_ID, "🐈", null), - fakeChunk([ + fakeReactions([ {key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈", sender: "@cadence:cadence.moe"}, {key: "🐈‍⬛", sender: "@zoe:cadence.moe"}, @@ -118,7 +116,7 @@ test("remove reaction: a specific reaction leads to all matrix users' reaction o test("remove reaction: an emoji removes all instances of the emoij from both sides", t => { const removals = removeReaction.removeEmojiReaction( fakeEmojiReactionRemoval("🐈", null), - fakeChunk([ + fakeReactions([ {key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈", sender: "@cadence:cadence.moe"}, {key: "🐈‍⬛", sender: "@zoe:cadence.moe"}, @@ -145,7 +143,7 @@ test("remove reaction: an emoji removes all instances of the emoij from both sid test("remove reaction: remove all removes all from both sides", t => { const removals = removeReaction.removeAllReactions( fakeAllReactionRemoval(), - fakeChunk([ + fakeReactions([ {key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈", sender: "@cadence:cadence.moe"}, {key: "🐈‍⬛", sender: "@zoe:cadence.moe"}, diff --git a/matrix/api.js b/matrix/api.js index 7ec044a..5509930 100644 --- a/matrix/api.js +++ b/matrix/api.js @@ -112,12 +112,16 @@ function getJoinedMembers(roomID) { /** * @param {string} roomID * @param {string} eventID + * @param {{from?: string, limit?: any}} pagination * @param {string?} [relType] * @returns {Promise>>} */ -function getRelations(roomID, eventID, relType) { +function getRelations(roomID, eventID, pagination, relType) { let path = `/client/v1/rooms/${roomID}/relations/${eventID}` if (relType) path += `/${relType}` + if (!pagination.from) delete pagination.from + if (!pagination.limit) pagination.limit = 50 // get a little more consistency between homeservers + path += `?${new URLSearchParams(pagination)}` return mreq.mreq("GET", path) }