make removing single reactions work correctly
This commit is contained in:
		| @@ -10,8 +10,9 @@ const api = sync.require("../../matrix/api") | ||||
| const registerUser = sync.require("./register-user") | ||||
| /** @type {import("../actions/create-room")} */ | ||||
| const createRoom = sync.require("../actions/create-room") | ||||
| /** @type {import("../../matrix/file")} */ | ||||
| const file = sync.require("../../matrix/file") | ||||
| /** @type {import("../converters/emoji-to-key")} */ | ||||
| const emojiToKey = sync.require("../converters/emoji-to-key") | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data | ||||
| @@ -24,24 +25,7 @@ async function addReaction(data) { | ||||
| 	if (!parentID) return // Nothing can be done if the parent message was never bridged. | ||||
| 	assert.equal(typeof parentID, "string") | ||||
|  | ||||
| 	let key | ||||
| 	if (data.emoji.id) { | ||||
| 		// Custom emoji | ||||
| 		const mxc = select("emoji", "mxc_url", "WHERE id = ?").pluck().get(data.emoji.id) | ||||
| 		if (mxc) { | ||||
| 			// The custom emoji is registered and we should send it | ||||
| 			key = mxc | ||||
| 		} else { | ||||
| 			// The custom emoji is not registered. We will register it and then add it. | ||||
| 			const mxc = await file.uploadDiscordFileToMxc(file.emoji(data.emoji.id, data.emoji.animated)) | ||||
| 			db.prepare("INSERT OR IGNORE INTO emoji (id, name, animated, mxc_url) VALUES (?, ?, ?, ?)").run(data.emoji.id, data.emoji.name, +!!data.emoji.animated, mxc) | ||||
| 			key = mxc | ||||
| 			// TODO: what happens if the matrix user also tries adding this reaction? the bridge bot isn't able to use that emoji... | ||||
| 		} | ||||
| 	} else { | ||||
| 		// Default emoji | ||||
| 		key = data.emoji.name | ||||
| 	} | ||||
| 	const key = await emojiToKey.emojiToKey(data.emoji) | ||||
|  | ||||
| 	const roomID = await createRoom.ensureRoom(data.channel_id) | ||||
| 	const senderMxid = await registerUser.ensureSimJoined(user, roomID) | ||||
|   | ||||
| @@ -7,12 +7,8 @@ const passthrough = require("../../passthrough") | ||||
| const {discord, sync, db, select} = passthrough | ||||
| /** @type {import("../../matrix/api")} */ | ||||
| const api = sync.require("../../matrix/api") | ||||
| /** @type {import("./register-user")} */ | ||||
| const registerUser = sync.require("./register-user") | ||||
| /** @type {import("../actions/create-room")} */ | ||||
| const createRoom = sync.require("../actions/create-room") | ||||
| /** @type {import("../../matrix/file")} */ | ||||
| const file = sync.require("../../matrix/file") | ||||
| /** @type {import("../converters/emoji-to-key")} */ | ||||
| const emojiToKey = sync.require("../converters/emoji-to-key") | ||||
|  | ||||
| /** | ||||
|  * @param {import("discord-api-types/v10").GatewayMessageReactionRemoveDispatchData} data | ||||
| @@ -27,10 +23,11 @@ async function removeReaction(data) { | ||||
|  | ||||
| 	/** @type {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} */ | ||||
| 	const relations = await api.getRelations(roomID, eventIDForMessage, "m.annotation") | ||||
| 	const eventIDForReaction = relations.chunk.find(e => e.sender === mxid && e.content["m.relates_to"].key === data.emoji) // TODO: get the key from the emoji | ||||
| 	const key = await emojiToKey.emojiToKey(data.emoji) | ||||
| 	const eventIDForReaction = relations.chunk.find(e => e.sender === mxid && e.content["m.relates_to"].key === key) | ||||
| 	if (!eventIDForReaction) return | ||||
|  | ||||
| 	await api.redactEvent(roomID, eventIDForReaction, mxid) | ||||
| 	await api.redactEvent(roomID, eventIDForReaction.event_id, mxid) | ||||
| } | ||||
|  | ||||
| module.exports.removeReaction = removeReaction | ||||
|   | ||||
							
								
								
									
										38
									
								
								d2m/converters/emoji-to-key.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								d2m/converters/emoji-to-key.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| // @ts-check | ||||
|  | ||||
| const assert = require("assert").strict | ||||
| const passthrough = require("../../passthrough") | ||||
| const {discord, sync, db, select} = passthrough | ||||
| /** @type {import("../../matrix/file")} */ | ||||
| const file = sync.require("../../matrix/file") | ||||
|  | ||||
| /** | ||||
|  * @param {import("discord-api-types/v10").APIEmoji} emoji | ||||
|  * @returns {Promise<string>} | ||||
|  */ | ||||
| async function emojiToKey(emoji) { | ||||
| 	let key | ||||
| 	if (emoji.id) { | ||||
| 		// Custom emoji | ||||
| 		const mxc = select("emoji", "mxc_url", "WHERE id = ?").pluck().get(emoji.id) | ||||
| 		if (mxc) { | ||||
| 			// The custom emoji is registered and we should send it | ||||
| 			key = mxc | ||||
| 		} else { | ||||
| 			// The custom emoji is not registered. We will register it and then add it. | ||||
| 			assert(emoji.name) // The docs say: "name may be null when custom emoji data is not available, for example, if it was deleted from the guild" | ||||
| 			const mxc = await file.uploadDiscordFileToMxc(file.emoji(emoji.id, emoji.animated)) | ||||
| 			db.prepare("INSERT OR IGNORE INTO emoji (id, name, animated, mxc_url) VALUES (?, ?, ?, ?)").run(emoji.id, emoji.name, +!!emoji.animated, mxc) | ||||
| 			key = mxc | ||||
| 			// TODO: what happens if the matrix user also tries adding this reaction? the bridge bot isn't able to use that emoji... | ||||
| 		} | ||||
| 	} else { | ||||
| 		// Default emoji | ||||
| 		const name = emoji.name | ||||
| 		assert(name) | ||||
| 		key = name | ||||
| 	} | ||||
| 	return key | ||||
| } | ||||
|  | ||||
| module.exports.emojiToKey = emojiToKey | ||||
| @@ -155,6 +155,9 @@ const utils = { | ||||
|  | ||||
| 				} else if (message.t === "MESSAGE_REACTION_ADD") { | ||||
| 					await eventDispatcher.onReactionAdd(client, message.d) | ||||
|  | ||||
| 				} else if (message.t === "MESSAGE_REACTION_REMOVE") { | ||||
| 					await eventDispatcher.onReactionRemove(client, message.d) | ||||
| 				} | ||||
| 			} catch (e) { | ||||
| 				// Let OOYE try to handle errors too | ||||
|   | ||||
| @@ -10,6 +10,8 @@ const editMessage = sync.require("./actions/edit-message") | ||||
| const deleteMessage = sync.require("./actions/delete-message") | ||||
| /** @type {import("./actions/add-reaction")}) */ | ||||
| const addReaction = sync.require("./actions/add-reaction") | ||||
| /** @type {import("./actions/remove-reaction")}) */ | ||||
| const removeReaction = sync.require("./actions/remove-reaction") | ||||
| /** @type {import("./actions/announce-thread")}) */ | ||||
| const announceThread = sync.require("./actions/announce-thread") | ||||
| /** @type {import("./actions/create-room")}) */ | ||||
| @@ -210,6 +212,15 @@ module.exports = { | ||||
| 		await addReaction.addReaction(data) | ||||
| 	}, | ||||
|  | ||||
| 	/** | ||||
| 	 * @param {import("./discord-client")} client | ||||
| 	 * @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data | ||||
| 	 */ | ||||
| 	async onReactionRemove(client, data) { | ||||
| 		if (data.user_id === client.user.id) return // m2d reactions are added by the discord bot user - do not reflect them back to matrix. | ||||
| 		await removeReaction.removeReaction(data) | ||||
| 	}, | ||||
|  | ||||
| 	/** | ||||
| 	 * @param {import("./discord-client")} client | ||||
| 	 * @param {import("discord-api-types/v10").GatewayMessageDeleteDispatchData} data | ||||
|   | ||||
| @@ -24,7 +24,8 @@ async function removeReaction(event) { | ||||
| 	const hash = utils.getEventIDHash(event.redacts) | ||||
| 	const row = from("reaction").join("message_channel", "message_id").select("channel_id", "message_id", "encoded_emoji").and("WHERE hashed_event_id = ?").get(hash) | ||||
| 	if (!row) return | ||||
| 	return discord.snow.channel.deleteReactionSelf(row.channel_id, row.message_id, row.encoded_emoji) | ||||
| 	await discord.snow.channel.deleteReactionSelf(row.channel_id, row.message_id, row.encoded_emoji) | ||||
| 	db.prepare("DELETE FROM reaction WHERE hashed_event_id = ?").run(hash) | ||||
| } | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -155,7 +155,10 @@ async function sendEvent(roomID, type, content, mxid, timestamp) { | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @returns {Promise<string>} room ID | ||||
|  * @param {string} roomID | ||||
|  * @param {string} eventID | ||||
|  * @param {string?} [mxid] | ||||
|  * @returns {Promise<string>} event ID | ||||
|  */ | ||||
| async function redactEvent(roomID, eventID, mxid) { | ||||
| 	/** @type {Ty.R.EventRedacted} */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Cadence Ember
					Cadence Ember