From 55da70f8fce8de8e801b7bae940f7de34ab47fdd Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Mon, 28 Aug 2023 01:30:07 +1200 Subject: [PATCH] m->d start coding message edits --- m2d/actions/send-event.js | 8 +++-- m2d/converters/event-to-message.js | 50 ++++++++++++++++++++++++++++-- types.d.ts | 2 ++ 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/m2d/actions/send-event.js b/m2d/actions/send-event.js index 016768e..3aa6346 100644 --- a/m2d/actions/send-event.js +++ b/m2d/actions/send-event.js @@ -29,13 +29,15 @@ async function sendEvent(event) { // no need to sync the matrix member to the other side. but if I did need to, this is where I'd do it - const messages = await eventToMessage.eventToMessage(event, guild, {api}) - assert(Array.isArray(messages)) // sanity + const {messagesToEdit, messagesToSend, messagesToDelete} = await eventToMessage.eventToMessage(event, guild, {api}) /** @type {DiscordTypes.APIMessage[]} */ const messageResponses = [] let eventPart = 0 // 0 is primary, 1 is supporting - for (const message of messages) { + // for (const message of messagesToEdit) { + // eventPart = 1 + // TODO ... + for (const message of messagesToSend) { const messageResponse = await channelWebhook.sendMessageWithWebhook(channelID, message, threadID) db.prepare("INSERT INTO event_message (event_id, event_type, event_subtype, message_id, channel_id, part, source) VALUES (?, ?, ?, ?, ?, ?, 0)").run(event.event_id, event.type, event.content.msgtype || null, messageResponse.id, channelID, eventPart) // source 0 = matrix diff --git a/m2d/converters/event-to-message.js b/m2d/converters/event-to-message.js index 534becb..70a0a69 100644 --- a/m2d/converters/event-to-message.js +++ b/m2d/converters/event-to-message.js @@ -130,6 +130,8 @@ async function eventToMessage(event, guild, di) { let displayName = event.sender let avatarURL = undefined + /** @type {string[]} */ + let messageIDsToEdit = [] let replyLine = "" // Extract a basic display name from the sender const match = event.sender.match(/^@(.*?):/) @@ -152,9 +154,37 @@ async function eventToMessage(event, guild, di) { // input = input.replace(/ /g, " ") // There is also a corresponding test to uncomment, named "event2message: whitespace is retained" - // Handling replies. We'll look up the data of the replied-to event from the Matrix homeserver. + // Handling edits. If the edit was an edit of a reply, edits do not include the reply reference, so we need to fetch up to 2 more events. + // this event ---is an edit of--> original event ---is a reply to--> past event await (async () => { - const repliedToEventId = event.content["m.relates_to"]?.["m.in_reply_to"].event_id + if (!event.content["m.new_content"]) return + const relatesTo = event.content["m.relates_to"] + if (!relatesTo) return + // Check if we have a pointer to what was edited + const relType = relatesTo.rel_type + if (relType !== "m.replace") return + const originalEventId = relatesTo.event_id + if (!originalEventId) return + console.log("a", originalEventId) + messageIDsToEdit = db.prepare("SELECT message_id FROM event_message WHERE event_id = ? ORDER BY part").pluck().all(originalEventId) + if (!messageIDsToEdit.length) return + // Get the original event, then check if it was a reply + const originalEvent = await di.api.getEvent(event.room_id, originalEventId) + if (!originalEvent) return + const repliedToEventId = originalEvent.content["m.relates_to"]?.["m.in_reply_to"]?.event_id + if (!repliedToEventId) return + console.log("c") + // After all that, it's an edit of a reply. + // We'll be sneaky and prepare the message data so that everything else can handle it just like original messages. + Object.assign(event.content, event.content["m.new_content"]) + input = event.content.formatted_body || event.content.body + relatesTo["m.in_reply_to"] = {event_id: repliedToEventId} + })() + + // Handling replies. We'll look up the data of the replied-to event from the Matrix homeserver. + // Note that an element is not guaranteed because this might be m.new_content. + await (async () => { + const repliedToEventId = event.content["m.relates_to"]?.["m.in_reply_to"]?.event_id if (!repliedToEventId) return const repliedToEvent = await di.api.getEvent(event.room_id, repliedToEventId) if (!repliedToEvent) return @@ -235,7 +265,21 @@ async function eventToMessage(event, guild, di) { avatar_url: avatarURL }))) - return messages + const messagesToEdit = [] + const messagesToSend = [] + for (let i = 0; i < messages.length; i++) { + if (messageIDsToEdit.length) { + messagesToEdit.push({id: messageIDsToEdit.shift(), message: messages[i]}) + } else { + messagesToSend.push(messages[i]) + } + } + + return { + messagesToEdit, + messagesToSend, + messagesToDelete: messageIDsToEdit + } } module.exports.eventToMessage = eventToMessage diff --git a/types.d.ts b/types.d.ts index 5475904..dcde3ad 100644 --- a/types.d.ts +++ b/types.d.ts @@ -75,6 +75,8 @@ export namespace Event { "m.in_reply_to": { event_id: string } + rel_type?: "m.replace" + event_id?: string } }