diff --git a/db/ooye-test-data.sql b/db/ooye-test-data.sql index ef66593..bb789b2 100644 --- a/db/ooye-test-data.sql +++ b/db/ooye-test-data.sql @@ -32,9 +32,7 @@ INSERT INTO message_channel (message_id, channel_id) VALUES ('1141619794500649020', '497161350934560778'), ('1143121514925928541', '1100319550446252084'), ('1144865310588014633', '687028734322147344'), -('1145688633186193479', '1100319550446252084'), -('1145688633186193480', '1100319550446252084'), -('1145688633186193481', '1100319550446252084'); +('1145688633186193479', '1100319550446252084'); INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part, source) VALUES ('$X16nfVks1wsrhq4E9SSLiqrf2N8KD0erD0scZG7U5xg', 'm.room.message', 'm.text', '1126786462646550579', 0, 1), @@ -53,9 +51,7 @@ INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part ('$f9cjKiacXI9qPF_nUAckzbiKnJEi0LM399kOkhdd8f8', 'm.sticker', NULL, '1106366167788044450', 0, 0), ('$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04', 'm.room.message', 'm.text', '1144865310588014633', 0, 1), ('$v_Gtr-bzv9IVlSLBO5DstzwmiDd-GSFaNfHX66IupV8', 'm.room.message', 'm.text', '1144874214311067708', 0, 0), -('$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSs', 'm.room.message', 'm.text', '1145688633186193479', 0, 0), -('$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSt', 'm.room.message', 'm.text', '1145688633186193480', 0, 0), -('$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSt', 'm.room.message', 'm.text', '1145688633186193481', 1, 0); +('$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSs', 'm.room.message', 'm.text', '1145688633186193479', 0, 0); INSERT INTO file (discord_url, mxc_url) VALUES ('https://cdn.discordapp.com/attachments/497161332244742154/1124628646431297546/image.png', 'mxc://cadence.moe/qXoZktDqNtEGuOCZEADAMvhM'), @@ -70,7 +66,7 @@ INSERT INTO file (discord_url, mxc_url) VALUES INSERT INTO member_cache (room_id, mxid, displayname, avatar_url) VALUES ('!kLRqKKUQXcibIMtOpl:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', NULL), -('!BpMdOUkWWhFxmTrENV:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'malformed mxc'), +('!BpMdOUkWWhFxmTrENV:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', NULL), ('!fGgIymcYWOqjbSRUdV:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU'), ('!PnyBKvUBOhjuCucEfk:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU'); diff --git a/m2d/actions/channel-webhook.js b/m2d/actions/channel-webhook.js index eabec52..404b555 100644 --- a/m2d/actions/channel-webhook.js +++ b/m2d/actions/channel-webhook.js @@ -71,20 +71,7 @@ async function editMessageWithWebhook(channelID, messageID, data, threadID) { return result } -/** - * @param {string} channelID - * @param {string} messageID - * @param {string} [threadID] - */ -async function deleteMessageWithWebhook(channelID, messageID, threadID) { - const result = await withWebhook(channelID, async webhook => { - return discord.snow.webhook.deleteWebhookMessage(webhook.id, webhook.token, messageID, threadID) - }) - return result -} - module.exports.ensureWebhook = ensureWebhook module.exports.withWebhook = withWebhook module.exports.sendMessageWithWebhook = sendMessageWithWebhook module.exports.editMessageWithWebhook = editMessageWithWebhook -module.exports.deleteMessageWithWebhook = deleteMessageWithWebhook diff --git a/m2d/actions/send-event.js b/m2d/actions/send-event.js index 18a1e0f..2667d26 100644 --- a/m2d/actions/send-event.js +++ b/m2d/actions/send-event.js @@ -31,26 +31,20 @@ async function sendEvent(event) { const {messagesToEdit, messagesToSend, messagesToDelete} = await eventToMessage.eventToMessage(event, guild, {api}) - let eventPart = 0 // 0 is primary, 1 is supporting - /** @type {DiscordTypes.APIMessage[]} */ const messageResponses = [] + let eventPart = 0 // 0 is primary, 1 is supporting for (const data of messagesToEdit) { const messageResponse = await channelWebhook.editMessageWithWebhook(channelID, data.id, data.message, threadID) eventPart = 1 messageResponses.push(messageResponse) } - - for (const id of messagesToDelete) { - await channelWebhook.deleteMessageWithWebhook(channelID, id, threadID) - } - for (const message of messagesToSend) { const messageResponse = await channelWebhook.sendMessageWithWebhook(channelID, message, threadID) db.prepare("REPLACE INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(messageResponse.id, channelID) db.prepare("INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part, source) VALUES (?, ?, ?, ?, ?, 0)").run(event.event_id, event.type, event.content.msgtype || null, messageResponse.id, eventPart) // source 0 = matrix - eventPart = 1 + eventPart = 1 // TODO: use more intelligent algorithm to determine whether primary or supporting? messageResponses.push(messageResponse) } diff --git a/m2d/converters/event-to-message.js b/m2d/converters/event-to-message.js index 3e77560..9c221a5 100644 --- a/m2d/converters/event-to-message.js +++ b/m2d/converters/event-to-message.js @@ -21,6 +21,10 @@ const BLOCK_ELEMENTS = [ "TFOOT", "TH", "THEAD", "TR", "UL" ] +function cleanAttribute (attribute) { + return attribute ? attribute.replace(/(\n+\s*)+/g, "\n") : "" +} + const turndownService = new TurndownService({ hr: "----", headingStyle: "atx", @@ -76,9 +80,11 @@ turndownService.addRule("inlineLink", { if (node.getAttribute("data-user-id")) return `<@${node.getAttribute("data-user-id")}>` if (node.getAttribute("data-channel-id")) return `<#${node.getAttribute("data-channel-id")}>` const href = node.getAttribute("href") + let title = cleanAttribute(node.getAttribute("title")) + if (title) title = ` "` + title + `"` let brackets = ["", ""] if (href.startsWith("https://matrix.to")) brackets = ["<", ">"] - return "[" + content + "](" + brackets[0] + href + brackets[1] + ")" + return "[" + content + "](" + brackets[0] + href + title + brackets[1] + ")" } }) @@ -298,11 +304,6 @@ async function eventToMessage(event, guild, di) { } } - // Ensure there is code coverage for adding, editing, and deleting - if (messagesToSend.length) void 0 - if (messagesToEdit.length) void 0 - if (messageIDsToEdit.length) void 0 - return { messagesToEdit, messagesToSend, diff --git a/m2d/converters/event-to-message.test.js b/m2d/converters/event-to-message.test.js index 411d97c..41bb2e7 100644 --- a/m2d/converters/event-to-message.test.js +++ b/m2d/converters/event-to-message.test.js @@ -1,8 +1,6 @@ const {test} = require("supertape") const {eventToMessage} = require("./event-to-message") const data = require("../../test/data") -const {MatrixServerError} = require("../../matrix/mreq") -const {db} = require("../../passthrough") /** * @param {string} roomID @@ -99,7 +97,7 @@ test("event2message: basic html is converted to markdown", async t => { msgtype: "m.text", body: "wrong body", format: "org.matrix.custom.html", - formatted_body: "this is a test of formatting" + formatted_body: "this is a test of formatting" }, event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU", origin_server_ts: 1688301929913, @@ -115,7 +113,7 @@ test("event2message: basic html is converted to markdown", async t => { messagesToEdit: [], messagesToSend: [{ username: "cadence [they]", - content: "this **is** a _**test** __of___ ~~formatting~~", + content: "this **is** a **_test_** of ~~formatting~~", avatar_url: undefined }] } @@ -428,34 +426,6 @@ test("event2message: quotes have an appropriate amount of whitespace", async t = ) }) -test("event2message: m.emote plaintext works", async t => { - t.deepEqual( - await eventToMessage({ - content: { - msgtype: "m.emote", - body: "tests an m.emote message" - }, - event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU", - origin_server_ts: 1688301929913, - room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe", - sender: "@cadence:cadence.moe", - type: "m.room.message", - unsigned: { - age: 405299 - } - }), - { - messagesToDelete: [], - messagesToEdit: [], - messagesToSend: [{ - username: "cadence [they]", - content: "\\* cadence [they] tests an m.emote message", - avatar_url: undefined - }] - } - ) -}) - test("event2message: m.emote markdown syntax is escaped", async t => { t.deepEqual( await eventToMessage({ @@ -669,112 +639,6 @@ test("event2message: editing a plaintext body message", async t => { ) }) -test("event2message: editing a plaintext message to be longer", async t => { - t.deepEqual( - await eventToMessage({ - "type": "m.room.message", - "sender": "@cadence:cadence.moe", - "content": { - "msgtype": "m.text", - "body": " * " + "aaaaaaaaa ".repeat(198) + "well, I guess it's no longer brand new... it's existed for mere seconds..." + "aaaaaaaaa ".repeat(20), - "m.new_content": { - "msgtype": "m.text", - "body": "aaaaaaaaa ".repeat(198) + "well, I guess it's no longer brand new... it's existed for mere seconds..." + "aaaaaaaaa ".repeat(20) - }, - "m.relates_to": { - "rel_type": "m.replace", - "event_id": "$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSs" - } - }, - "origin_server_ts": 1693223873912, - "unsigned": { - "age": 42, - "transaction_id": "m1693223873796.842" - }, - "event_id": "$KxGwvVNzNcmlVbiI2m5kX-jMFNi3Jle71-uu1j7P7vM", - "room_id": "!PnyBKvUBOhjuCucEfk:cadence.moe" - }, data.guild.general, { - api: { - getEvent: mockGetEvent(t, "!PnyBKvUBOhjuCucEfk:cadence.moe", "$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSs", { - type: "m.room.message", - sender: "@cadence:cadence.moe", - content: { - msgtype: "m.text", - body: "brand new, never before seen message", - } - }) - } - }), - { - messagesToDelete: [], - messagesToEdit: [{ - id: "1145688633186193479", - message: { - content: "aaaaaaaaa ".repeat(198) + "well, I guess it's", - username: "cadence [they]", - avatar_url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/azCAhThKTojXSZJRoWwZmhvU" - } - }], - messagesToSend: [{ - content: "no longer brand new... it's existed for mere seconds..." + ("aaaaaaaaa ".repeat(20)).slice(0, -1), - username: "cadence [they]", - avatar_url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/azCAhThKTojXSZJRoWwZmhvU" - }] - } - ) -}) - -test("event2message: editing a plaintext message to be shorter", async t => { - t.deepEqual( - await eventToMessage({ - "type": "m.room.message", - "sender": "@cadence:cadence.moe", - "content": { - "msgtype": "m.text", - "body": " * well, I guess it's no longer brand new... it's existed for mere seconds...", - "m.new_content": { - "msgtype": "m.text", - "body": "well, I guess it's no longer brand new... it's existed for mere seconds..." - }, - "m.relates_to": { - "rel_type": "m.replace", - "event_id": "$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSt" - } - }, - "origin_server_ts": 1693223873912, - "unsigned": { - "age": 42, - "transaction_id": "m1693223873796.842" - }, - "event_id": "$KxGwvVNzNcmlVbiI2m5kX-jMFNi3Jle71-uu1j7P7vM", - "room_id": "!PnyBKvUBOhjuCucEfk:cadence.moe" - }, data.guild.general, { - api: { - getEvent: mockGetEvent(t, "!PnyBKvUBOhjuCucEfk:cadence.moe", "$7LIdiJCEqjcWUrpzWzS8TELOlFfBEe4ytgS7zn2lbSt", { - type: "m.room.message", - sender: "@cadence:cadence.moe", - content: { - msgtype: "m.text", - body: "aaaaaaaaa ".repeat(198) + "well, I guess it's no longer brand new... it's existed for mere seconds..." + "aaaaaaaaa ".repeat(20) - } - }) - } - }), - { - messagesToDelete: ["1145688633186193481"], - messagesToEdit: [{ - id: "1145688633186193480", - message: { - username: "cadence [they]", - content: "well, I guess it's no longer brand new... it's existed for mere seconds...", - avatar_url: "https://matrix.cadence.moe/_matrix/media/r0/download/cadence.moe/azCAhThKTojXSZJRoWwZmhvU" - } - }], - messagesToSend: [] - } - ) -}) - test("event2message: editing a formatted body message", async t => { t.deepEqual( await eventToMessage({ @@ -1001,7 +865,7 @@ test("event2message: mentioning bridged rooms works", async t => { msgtype: "m.text", body: "wrong body", format: "org.matrix.custom.html", - formatted_body: `I'm just worm-form testing channel mentions` + formatted_body: `I'm just testing mentions` }, event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU", origin_server_ts: 1688301929913, @@ -1017,96 +881,9 @@ test("event2message: mentioning bridged rooms works", async t => { messagesToEdit: [], messagesToSend: [{ username: "cadence [they]", - content: "I'm just <#1100319550446252084> testing channel mentions", + content: "I'm just [▲]() testing mentions", avatar_url: undefined }] } ) }) - -test("event2message: caches the member if the member is not known", async t => { - let called = 0 - t.deepEqual( - await eventToMessage({ - content: { - body: "testing the member state cache", - msgtype: "m.text" - }, - event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU", - origin_server_ts: 1688301929913, - room_id: "!should_be_newly_cached:cadence.moe", - sender: "@should_be_newly_cached:cadence.moe", - type: "m.room.message", - unsigned: { - age: 405299 - } - }, {}, { - api: { - getStateEvent: async (roomID, type, stateKey) => { - called++ - t.equal(roomID, "!should_be_newly_cached:cadence.moe") - t.equal(type, "m.room.member") - t.equal(stateKey, "@should_be_newly_cached:cadence.moe") - return { - displayname: "this is the username", - avatar_url: undefined - } - } - } - }), - { - messagesToDelete: [], - messagesToEdit: [], - messagesToSend: [{ - username: "this is the username", - content: "testing the member state cache", - avatar_url: undefined - }] - } - ) - t.deepEqual(db.prepare("SELECT avatar_url, displayname, mxid FROM member_cache WHERE room_id = '!should_be_newly_cached:cadence.moe'").all(), [ - {avatar_url: null, displayname: "this is the username", mxid: "@should_be_newly_cached:cadence.moe"} - ]) - t.equal(called, 1, "getStateEvent should be called once") -}) - -test("event2message: skips caching the member if the member does not exist, somehow", async t => { - let called = 0 - t.deepEqual( - await eventToMessage({ - content: { - body: "should honestly never happen", - msgtype: "m.text" - }, - event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU", - origin_server_ts: 1688301929913, - room_id: "!not_real:cadence.moe", - sender: "@not_real:cadence.moe", - type: "m.room.message", - unsigned: { - age: 405299 - } - }, {}, { - api: { - getStateEvent: async (roomID, type, stateKey) => { - called++ - t.equal(roomID, "!not_real:cadence.moe") - t.equal(type, "m.room.member") - t.equal(stateKey, "@not_real:cadence.moe") - throw new MatrixServerError("State event doesn't exist or something") - } - } - }), - { - messagesToDelete: [], - messagesToEdit: [], - messagesToSend: [{ - username: "not_real", - content: "should honestly never happen", - avatar_url: undefined - }] - } - ) - t.deepEqual(db.prepare("SELECT avatar_url, displayname, mxid FROM member_cache WHERE room_id = '!not_real:cadence.moe'").all(), []) - t.equal(called, 1, "getStateEvent should be called once") -})