Only edit events if the text has changed
This commit is contained in:
parent
954d41269c
commit
c71044fdec
2 changed files with 83 additions and 31 deletions
|
@ -22,6 +22,10 @@ function eventCanBeEdited(ev) {
|
|||
return true
|
||||
}
|
||||
|
||||
function eventIsText(ev) {
|
||||
return ev.old.event_type === "m.room.message" && (ev.old.event_subtype === "m.text" || ev.old.event_subtype === "m.notice")
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message
|
||||
* @param {import("discord-api-types/v10").APIGuild} guild
|
||||
|
@ -121,6 +125,20 @@ async function editToChanges(message, guild, api) {
|
|||
unchangedEvents.push(...eventsToReplace.filter(ev => !eventCanBeEdited(ev))) // Move them from eventsToRedact to unchangedEvents.
|
||||
eventsToReplace = eventsToReplace.filter(eventCanBeEdited)
|
||||
|
||||
// Now, everything in eventsToReplace has the potential to have changed, but did it actually?
|
||||
// (Example: if a URL preview was generated or updated, the message text won't have changed.)
|
||||
// Only way to detect this is by text content. So we'll remove text events from eventsToReplace that have the same new text as text currently in the event.
|
||||
for (let i = eventsToReplace.length; i--;) { // move backwards through array
|
||||
const event = eventsToReplace[i]
|
||||
if (!eventIsText(event)) continue // not text, can't analyse
|
||||
const oldEvent = await api.getEvent(roomID, eventsToReplace[i].old.event_id)
|
||||
const oldEventBodyWithoutQuotedReply = oldEvent.content.body?.replace(/^(>.*\n)*\n*/sm, "")
|
||||
if (oldEventBodyWithoutQuotedReply !== event.newInnerContent.body) continue // event changed, must replace it
|
||||
// Move it from eventsToRedact to unchangedEvents.
|
||||
unchangedEvents.push(...eventsToReplace.filter(ev => ev.old.event_id === event.old.event_id))
|
||||
eventsToReplace = eventsToReplace.filter(ev => ev.old.event_id !== event.old.event_id)
|
||||
}
|
||||
|
||||
// We want to maintain exactly one part = 0 and one reaction_part = 0 database row at all times.
|
||||
// This would be disrupted if existing events that are (reaction_)part = 0 will be redacted.
|
||||
// If that is the case, pick a different existing or newly sent event to be (reaction_)part = 0.
|
||||
|
@ -193,4 +211,3 @@ function makeReplacementEventContent(oldID, newFallbackContent, newInnerContent)
|
|||
}
|
||||
|
||||
module.exports.editToChanges = editToChanges
|
||||
module.exports.makeReplacementEventContent = makeReplacementEventContent
|
||||
|
|
|
@ -4,7 +4,14 @@ const data = require("../../../test/data")
|
|||
const Ty = require("../../types")
|
||||
|
||||
test("edit2changes: edit by webhook", async t => {
|
||||
const {senderMxid, eventsToRedact, eventsToReplace, eventsToSend, promotions} = await editToChanges(data.message_update.edit_by_webhook, data.guild.general, {})
|
||||
let called = 0
|
||||
const {senderMxid, eventsToRedact, eventsToReplace, eventsToSend, promotions} = await editToChanges(data.message_update.edit_by_webhook, data.guild.general, {
|
||||
getEvent(roomID, eventID) {
|
||||
called++
|
||||
t.equal(eventID, "$zXSlyI78DQqQwwfPUSzZ1b-nXzbUrCDljJgnGDdoI10")
|
||||
return {content: {body: "dummy"}}
|
||||
}
|
||||
})
|
||||
t.deepEqual(eventsToRedact, [])
|
||||
t.deepEqual(eventsToSend, [])
|
||||
t.deepEqual(eventsToReplace, [{
|
||||
|
@ -28,10 +35,15 @@ test("edit2changes: edit by webhook", async t => {
|
|||
}])
|
||||
t.equal(senderMxid, null)
|
||||
t.deepEqual(promotions, [])
|
||||
t.equal(called, 1)
|
||||
})
|
||||
|
||||
test("edit2changes: bot response", async t => {
|
||||
const {senderMxid, eventsToRedact, eventsToReplace, eventsToSend, promotions} = await editToChanges(data.message_update.bot_response, data.guild.general, {
|
||||
getEvent(roomID, eventID) {
|
||||
t.equal(eventID, "$fdD9OZ55xg3EAsfvLZza5tMhtjUO91Wg3Otuo96TplY")
|
||||
return {content: {body: "dummy"}}
|
||||
},
|
||||
async getJoinedMembers(roomID) {
|
||||
t.equal(roomID, "!hYnGGlPHlbujVVfktC:cadence.moe")
|
||||
return new Promise(resolve => {
|
||||
|
@ -123,7 +135,14 @@ test("edit2changes: add caption back to that image (due to it having a reaction,
|
|||
})
|
||||
|
||||
test("edit2changes: stickers and attachments are not changed, only the content can be edited", async t => {
|
||||
const {eventsToRedact, eventsToReplace, eventsToSend} = await editToChanges(data.message_update.edited_content_with_sticker_and_attachments, data.guild.general, {})
|
||||
let called = 0
|
||||
const {eventsToRedact, eventsToReplace, eventsToSend} = await editToChanges(data.message_update.edited_content_with_sticker_and_attachments, data.guild.general, {
|
||||
getEvent(roomID, eventID) {
|
||||
called++
|
||||
t.equal(eventID, "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qdFv4")
|
||||
return {content: {body: "dummy"}}
|
||||
}
|
||||
})
|
||||
t.deepEqual(eventsToRedact, [])
|
||||
t.deepEqual(eventsToSend, [])
|
||||
t.deepEqual(eventsToReplace, [{
|
||||
|
@ -145,10 +164,16 @@ test("edit2changes: stickers and attachments are not changed, only the content c
|
|||
}
|
||||
}
|
||||
}])
|
||||
t.equal(called, 1)
|
||||
})
|
||||
|
||||
test("edit2changes: edit of reply to skull webp attachment with content", async t => {
|
||||
const {eventsToRedact, eventsToReplace, eventsToSend} = await editToChanges(data.message_update.edit_of_reply_to_skull_webp_attachment_with_content, data.guild.general, {})
|
||||
const {eventsToRedact, eventsToReplace, eventsToSend} = await editToChanges(data.message_update.edit_of_reply_to_skull_webp_attachment_with_content, data.guild.general, {
|
||||
getEvent(roomID, eventID) {
|
||||
t.equal(eventID, "$vgTKOR5ZTYNMKaS7XvgEIDaOWZtVCEyzLLi5Pc5Gz4M")
|
||||
return {content: {body: "dummy"}}
|
||||
}
|
||||
})
|
||||
t.deepEqual(eventsToRedact, [])
|
||||
t.deepEqual(eventsToSend, [])
|
||||
t.deepEqual(eventsToReplace, [{
|
||||
|
@ -177,7 +202,12 @@ test("edit2changes: edit of reply to skull webp attachment with content", async
|
|||
})
|
||||
|
||||
test("edit2changes: edits the text event when multiple rows have part = 0 (should never happen in real life, but make sure the safety net works)", async t => {
|
||||
const {eventsToRedact, eventsToReplace, eventsToSend} = await editToChanges(data.message_update.edited_content_with_sticker_and_attachments_but_all_parts_equal_0, data.guild.general, {})
|
||||
const {eventsToRedact, eventsToReplace, eventsToSend} = await editToChanges(data.message_update.edited_content_with_sticker_and_attachments_but_all_parts_equal_0, data.guild.general, {
|
||||
getEvent(roomID, eventID) {
|
||||
t.equal(eventID, "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qd999")
|
||||
return {content: {body: "dummy"}}
|
||||
}
|
||||
})
|
||||
t.deepEqual(eventsToRedact, [])
|
||||
t.deepEqual(eventsToSend, [])
|
||||
t.deepEqual(eventsToReplace, [{
|
||||
|
@ -202,7 +232,12 @@ test("edit2changes: edits the text event when multiple rows have part = 0 (shoul
|
|||
})
|
||||
|
||||
test("edit2changes: promotes the text event when multiple rows have part = 1 (should never happen in real life, but make sure the safety net works)", async t => {
|
||||
const {eventsToRedact, eventsToReplace, eventsToSend, promotions} = await editToChanges(data.message_update.edited_content_with_sticker_and_attachments_but_all_parts_equal_1, data.guild.general, {})
|
||||
const {eventsToRedact, eventsToReplace, eventsToSend, promotions} = await editToChanges(data.message_update.edited_content_with_sticker_and_attachments_but_all_parts_equal_1, data.guild.general, {
|
||||
getEvent(roomID, eventID) {
|
||||
t.equal(eventID, "$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qd111")
|
||||
return {content: {body: "dummy"}}
|
||||
}
|
||||
})
|
||||
t.deepEqual(eventsToRedact, [])
|
||||
t.deepEqual(eventsToSend, [])
|
||||
t.deepEqual(eventsToReplace, [{
|
||||
|
@ -279,32 +314,31 @@ test("edit2changes: generated embed", async t => {
|
|||
})
|
||||
|
||||
test("edit2changes: generated embed on a reply", async t => {
|
||||
const {senderMxid, eventsToRedact, eventsToReplace, eventsToSend, promotions} = await editToChanges(data.message_update.embed_generated_on_reply, data.guild.general, {})
|
||||
let called = 0
|
||||
const {senderMxid, eventsToRedact, eventsToReplace, eventsToSend, promotions} = await editToChanges(data.message_update.embed_generated_on_reply, data.guild.general, {
|
||||
getEvent(roomID, eventID) {
|
||||
called++
|
||||
t.equal(eventID, "$UTqiL3Zj3FC4qldxRLggN1fhygpKl8sZ7XGY5f9MNbF")
|
||||
return {
|
||||
type: "m.room.message",
|
||||
content: {
|
||||
// Unfortunately the edited message doesn't include the message_reference field. Fine. Whatever. It looks normal if you're using a good client.
|
||||
body: "> a Discord user: [Replied-to message content wasn't provided by Discord]"
|
||||
+ "\n\nhttps://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: "<mx-reply><blockquote><a href=\"https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM\">In reply to</a> a Discord user<br>[Replied-to message content wasn't provided by Discord]</blockquote></mx-reply><a href=\"https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM\">https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM</a>",
|
||||
"m.mentions": {},
|
||||
"m.relates_to": {
|
||||
event_id: "$UTqiL3Zj3FC4qldxRLggN1fhygpKl8sZ7XGY5f9MNbF",
|
||||
rel_type: "m.replace",
|
||||
},
|
||||
msgtype: "m.text",
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t.deepEqual(eventsToRedact, [])
|
||||
t.deepEqual(eventsToReplace, [{
|
||||
oldID: "$UTqiL3Zj3FC4qldxRLggN1fhygpKl8sZ7XGY5f9MNbF",
|
||||
newContent: {
|
||||
$type: "m.room.message",
|
||||
// Unfortunately the edited message doesn't include the message_reference field. Fine. Whatever. It looks normal if you're using a good client.
|
||||
body: "> a Discord user: [Replied-to message content wasn't provided by Discord]"
|
||||
+ "\n\n* https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: "<mx-reply><blockquote><a href=\"https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM\">In reply to</a> a Discord user<br>[Replied-to message content wasn't provided by Discord]</blockquote></mx-reply>* <a href=\"https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM\">https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM</a>",
|
||||
"m.mentions": {},
|
||||
"m.new_content": {
|
||||
body: "https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: "<a href=\"https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM\">https://matrix.to/#/!BnKuBPCvyfOkhcUjEu:cadence.moe/$aLVZyiC3HlOu-prCSIaXlQl68I8leUdnPFiCwkgn6qM</a>",
|
||||
"m.mentions": {},
|
||||
msgtype: "m.text",
|
||||
},
|
||||
"m.relates_to": {
|
||||
event_id: "$UTqiL3Zj3FC4qldxRLggN1fhygpKl8sZ7XGY5f9MNbF",
|
||||
rel_type: "m.replace",
|
||||
},
|
||||
msgtype: "m.text",
|
||||
},
|
||||
}])
|
||||
t.deepEqual(eventsToReplace, [])
|
||||
t.deepEqual(eventsToSend, [{
|
||||
$type: "m.room.message",
|
||||
msgtype: "m.notice",
|
||||
|
@ -324,4 +358,5 @@ test("edit2changes: generated embed on a reply", async t => {
|
|||
"nextEvent": true,
|
||||
}])
|
||||
t.equal(senderMxid, "@_ooye_cadence:cadence.moe")
|
||||
t.equal(called, 1)
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue