Paginate removing all reactions from Matrix-side

This commit is contained in:
Cadence Ember 2023-10-14 23:34:02 +13:00
parent c24752625d
commit 040e987d03
4 changed files with 56 additions and 46 deletions

View file

@ -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() const eventIDForMessage = select("event_message", "event_id", {message_id: data.message_id, reaction_part: 0}).pluck().get()
if (!eventIDForMessage) return if (!eventIDForMessage) return
/** @type {Ty.Event.Outer<Ty.Event.M_Reaction>[]} */
let reactions = []
/** @type {string | undefined} */
let nextBatch = undefined
do {
/** @type {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} */ /** @type {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} */
const relations = await api.getRelations(roomID, eventIDForMessage, "m.annotation") 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 // Run the proper strategy and any strategy-specific database changes
const removals = await const removals = await
( "user_id" in data ? removeReaction(data, relations) ( "user_id" in data ? removeReaction(data, reactions)
: "emoji" in data ? removeEmojiReaction(data, relations) : "emoji" in data ? removeEmojiReaction(data, reactions)
: removeAllReactions(data, relations)) : removeAllReactions(data, reactions))
// Redact the events and delete individual stored events in the database // Redact the events and delete individual stored events in the database
for (const removal of removals) { for (const removal of removals) {
@ -41,33 +49,33 @@ async function removeSomeReactions(data) {
/** /**
* @param {DiscordTypes.GatewayMessageReactionRemoveDispatchData} data * @param {DiscordTypes.GatewayMessageReactionRemoveDispatchData} data
* @param {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} relations * @param {Ty.Event.Outer<Ty.Event.M_Reaction>[]} reactions
*/ */
async function removeReaction(data, relations) { async function removeReaction(data, reactions) {
const key = await emojiToKey.emojiToKey(data.emoji) const key = await emojiToKey.emojiToKey(data.emoji)
return converter.removeReaction(data, relations, key) return converter.removeReaction(data, reactions, key)
} }
/** /**
* @param {DiscordTypes.GatewayMessageReactionRemoveEmojiDispatchData} data * @param {DiscordTypes.GatewayMessageReactionRemoveEmojiDispatchData} data
* @param {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} relations * @param {Ty.Event.Outer<Ty.Event.M_Reaction>[]} reactions
*/ */
async function removeEmojiReaction(data, relations) { async function removeEmojiReaction(data, reactions) {
const key = await emojiToKey.emojiToKey(data.emoji) const key = await emojiToKey.emojiToKey(data.emoji)
const discordPreferredEncoding = emoji.encodeEmoji(key, undefined) const discordPreferredEncoding = emoji.encodeEmoji(key, undefined)
db.prepare("DELETE FROM reaction WHERE message_id = ? AND encoded_emoji = ?").run(data.message_id, discordPreferredEncoding) 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 {DiscordTypes.GatewayMessageReactionRemoveAllDispatchData} data
* @param {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} relations * @param {Ty.Event.Outer<Ty.Event.M_Reaction>[]} reactions
*/ */
async function removeAllReactions(data, relations) { async function removeAllReactions(data, reactions) {
db.prepare("DELETE FROM reaction WHERE message_id = ?").run(data.message_id) 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 module.exports.removeSomeReactions = removeSomeReactions

View file

@ -17,15 +17,15 @@ const utils = sync.require("../../m2d/converters/utils")
/** /**
* @param {DiscordTypes.GatewayMessageReactionRemoveDispatchData} data * @param {DiscordTypes.GatewayMessageReactionRemoveDispatchData} data
* @param {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} relations * @param {Ty.Event.Outer<Ty.Event.M_Reaction>[]} reactions
* @param {string} key * @param {string} key
*/ */
function removeReaction(data, relations, key) { function removeReaction(data, reactions, key) {
/** @type {ReactionRemoveRequest[]} */ /** @type {ReactionRemoveRequest[]} */
const removals = [] const removals = []
const wantToRemoveMatrixReaction = data.user_id === discord.application.id const wantToRemoveMatrixReaction = data.user_id === discord.application.id
for (const event of relations.chunk) { for (const event of reactions) {
const eventID = event.event_id const eventID = event.event_id
if (event.content["m.relates_to"].key === key) { if (event.content["m.relates_to"].key === key) {
const lookingAtMatrixReaction = !utils.eventSenderIsFromDiscord(event.sender) const lookingAtMatrixReaction = !utils.eventSenderIsFromDiscord(event.sender)
@ -52,14 +52,14 @@ function removeReaction(data, relations, key) {
/** /**
* @param {DiscordTypes.GatewayMessageReactionRemoveEmojiDispatchData} data * @param {DiscordTypes.GatewayMessageReactionRemoveEmojiDispatchData} data
* @param {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} relations * @param {Ty.Event.Outer<Ty.Event.M_Reaction>[]} relations
* @param {string} key * @param {string} key
*/ */
function removeEmojiReaction(data, relations, key) { function removeEmojiReaction(data, relations, key) {
/** @type {ReactionRemoveRequest[]} */ /** @type {ReactionRemoveRequest[]} */
const removals = [] const removals = []
for (const event of relations.chunk) { for (const event of relations) {
const eventID = event.event_id const eventID = event.event_id
if (event.content["m.relates_to"].key === key) { if (event.content["m.relates_to"].key === key) {
const mxid = utils.eventSenderIsFromDiscord(event.sender) ? event.sender : null const mxid = utils.eventSenderIsFromDiscord(event.sender) ? event.sender : null
@ -72,11 +72,11 @@ function removeEmojiReaction(data, relations, key) {
/** /**
* @param {DiscordTypes.GatewayMessageReactionRemoveAllDispatchData} data * @param {DiscordTypes.GatewayMessageReactionRemoveAllDispatchData} data
* @param {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} relations * @param {Ty.Event.Outer<Ty.Event.M_Reaction>[]} relations
* @returns {ReactionRemoveRequest[]} * @returns {ReactionRemoveRequest[]}
*/ */
function removeAllReactions(data, relations) { function removeAllReactions(data, relations) {
return relations.chunk.map(event => { return relations.map(event => {
const eventID = event.event_id const eventID = event.event_id
const mxid = utils.eventSenderIsFromDiscord(event.sender) ? event.sender : null const mxid = utils.eventSenderIsFromDiscord(event.sender) ? event.sender : null
return {eventID, mxid} return {eventID, mxid}

View file

@ -29,9 +29,8 @@ function fakeAllReactionRemoval() {
} }
} }
function fakeChunk(chunk) { function fakeReactions(reactions) {
return { return reactions.map(({sender, key}, i) => ({
chunk: chunk.map(({sender, key}, i) => ({
content: { content: {
"m.relates_to": { "m.relates_to": {
rel_type: "m.annotation", rel_type: "m.annotation",
@ -46,13 +45,12 @@ function fakeChunk(chunk) {
room_id: "!THE_ROOM", room_id: "!THE_ROOM",
unsigned: null unsigned: null
})) }))
}
} }
test("remove reaction: a specific discord user's reaction is removed", t => { test("remove reaction: a specific discord user's reaction is removed", t => {
const removals = removeReaction.removeReaction( const removals = removeReaction.removeReaction(
fakeSpecificReactionRemoval("820865262526005258", "🐈", null), fakeSpecificReactionRemoval("820865262526005258", "🐈", null),
fakeChunk([{key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}]), fakeReactions([{key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}]),
"🐈" "🐈"
) )
t.deepEqual(removals, [{ 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 => { test("remove reaction: a specific matrix user's reaction is removed", t => {
const removals = removeReaction.removeReaction( const removals = removeReaction.removeReaction(
fakeSpecificReactionRemoval(BRIDGE_ID, "🐈", null), fakeSpecificReactionRemoval(BRIDGE_ID, "🐈", null),
fakeChunk([{key: "🐈", sender: "@cadence:cadence.moe"}]), fakeReactions([{key: "🐈", sender: "@cadence:cadence.moe"}]),
"🐈" "🐈"
) )
t.deepEqual(removals, [{ 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 => { test("remove reaction: a specific discord user's reaction is removed when there are multiple reactions", t => {
const removals = removeReaction.removeReaction( const removals = removeReaction.removeReaction(
fakeSpecificReactionRemoval("820865262526005258", "🐈", null), fakeSpecificReactionRemoval("820865262526005258", "🐈", null),
fakeChunk([ fakeReactions([
{key: "🐈‍⬛", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈‍⬛", sender: "@_ooye_crunch_god:cadence.moe"},
{key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"},
{key: "🐈", sender: "@_ooye_extremity: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 => { test("remove reaction: a specific reaction leads to all matrix users' reaction of the emoji being removed", t => {
const removals = removeReaction.removeReaction( const removals = removeReaction.removeReaction(
fakeSpecificReactionRemoval(BRIDGE_ID, "🐈", null), fakeSpecificReactionRemoval(BRIDGE_ID, "🐈", null),
fakeChunk([ fakeReactions([
{key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"},
{key: "🐈", sender: "@cadence:cadence.moe"}, {key: "🐈", sender: "@cadence:cadence.moe"},
{key: "🐈‍⬛", sender: "@zoe: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 => { test("remove reaction: an emoji removes all instances of the emoij from both sides", t => {
const removals = removeReaction.removeEmojiReaction( const removals = removeReaction.removeEmojiReaction(
fakeEmojiReactionRemoval("🐈", null), fakeEmojiReactionRemoval("🐈", null),
fakeChunk([ fakeReactions([
{key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"},
{key: "🐈", sender: "@cadence:cadence.moe"}, {key: "🐈", sender: "@cadence:cadence.moe"},
{key: "🐈‍⬛", sender: "@zoe: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 => { test("remove reaction: remove all removes all from both sides", t => {
const removals = removeReaction.removeAllReactions( const removals = removeReaction.removeAllReactions(
fakeAllReactionRemoval(), fakeAllReactionRemoval(),
fakeChunk([ fakeReactions([
{key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"}, {key: "🐈", sender: "@_ooye_crunch_god:cadence.moe"},
{key: "🐈", sender: "@cadence:cadence.moe"}, {key: "🐈", sender: "@cadence:cadence.moe"},
{key: "🐈‍⬛", sender: "@zoe:cadence.moe"}, {key: "🐈‍⬛", sender: "@zoe:cadence.moe"},

View file

@ -112,12 +112,16 @@ function getJoinedMembers(roomID) {
/** /**
* @param {string} roomID * @param {string} roomID
* @param {string} eventID * @param {string} eventID
* @param {{from?: string, limit?: any}} pagination
* @param {string?} [relType] * @param {string?} [relType]
* @returns {Promise<Ty.Pagination<Ty.Event.Outer<any>>>} * @returns {Promise<Ty.Pagination<Ty.Event.Outer<any>>>}
*/ */
function getRelations(roomID, eventID, relType) { function getRelations(roomID, eventID, pagination, relType) {
let path = `/client/v1/rooms/${roomID}/relations/${eventID}` let path = `/client/v1/rooms/${roomID}/relations/${eventID}`
if (relType) path += `/${relType}` 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) return mreq.mreq("GET", path)
} }