m->d rich replies
This commit is contained in:
		
							parent
							
								
									39fb4465f6
								
							
						
					
					
						commit
						0ea2b4efc9
					
				
					 4 changed files with 231 additions and 33 deletions
				
			
		| 
						 | 
					@ -67,7 +67,8 @@ INSERT INTO sim (discord_id, sim_name, localpart, mxid) VALUES
 | 
				
			||||||
('820865262526005258', 'crunch_god', '_ooye_crunch_god', '@_ooye_crunch_god:cadence.moe'),
 | 
					('820865262526005258', 'crunch_god', '_ooye_crunch_god', '@_ooye_crunch_god:cadence.moe'),
 | 
				
			||||||
('771520384671416320', 'bojack_horseman', '_ooye_bojack_horseman', '@_ooye_bojack_horseman:cadence.moe'),
 | 
					('771520384671416320', 'bojack_horseman', '_ooye_bojack_horseman', '@_ooye_bojack_horseman:cadence.moe'),
 | 
				
			||||||
('112890272819507200', '.wing.', '_ooye_.wing.', '@_ooye_.wing.:cadence.moe'),
 | 
					('112890272819507200', '.wing.', '_ooye_.wing.', '@_ooye_.wing.:cadence.moe'),
 | 
				
			||||||
('114147806469554185', 'extremity', '_ooye_extremity', '@_ooye_extremity:cadence.moe');
 | 
					('114147806469554185', 'extremity', '_ooye_extremity', '@_ooye_extremity:cadence.moe'),
 | 
				
			||||||
 | 
					('111604486476181504', 'kyuugryphon', '_ooye_kyuugryphon', '@_ooye_kyuugryphon:cadence.moe');;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
INSERT INTO sim_member (mxid, room_id, profile_event_content_hash) VALUES
 | 
					INSERT INTO sim_member (mxid, room_id, profile_event_content_hash) VALUES
 | 
				
			||||||
('@_ooye_bojack_horseman:cadence.moe', '!uCtjHhfGlYbVnPVlkG:cadence.moe', NULL);
 | 
					('@_ooye_bojack_horseman:cadence.moe', '!uCtjHhfGlYbVnPVlkG:cadence.moe', NULL);
 | 
				
			||||||
| 
						 | 
					@ -86,7 +87,8 @@ INSERT INTO event_message (event_id, event_type, event_subtype, message_id, chan
 | 
				
			||||||
('$FchUVylsOfmmbj-VwEs5Z9kY49_dt2zd0vWfylzy5Yo', 'm.room.message', 'm.text', '1143121514925928541', '1100319550446252084', 0, 1),
 | 
					('$FchUVylsOfmmbj-VwEs5Z9kY49_dt2zd0vWfylzy5Yo', 'm.room.message', 'm.text', '1143121514925928541', '1100319550446252084', 0, 1),
 | 
				
			||||||
('$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qdFv4', 'm.room.message', 'm.text', '1106366167788044450', '122155380120748034', 0, 1),
 | 
					('$lnAF9IosAECTnlv9p2e18FG8rHn-JgYKHEHIh5qdFv4', 'm.room.message', 'm.text', '1106366167788044450', '122155380120748034', 0, 1),
 | 
				
			||||||
('$Ijf1MFCD39ktrNHxrA-i2aKoRWNYdAV2ZXYQeiZIgEU', 'm.room.message', 'm.image', '1106366167788044450', '122155380120748034', 0, 0),
 | 
					('$Ijf1MFCD39ktrNHxrA-i2aKoRWNYdAV2ZXYQeiZIgEU', 'm.room.message', 'm.image', '1106366167788044450', '122155380120748034', 0, 0),
 | 
				
			||||||
('$f9cjKiacXI9qPF_nUAckzbiKnJEi0LM399kOkhdd8f8', 'm.sticker', NULL, '1106366167788044450', '122155380120748034', 0, 0);
 | 
					('$f9cjKiacXI9qPF_nUAckzbiKnJEi0LM399kOkhdd8f8', 'm.sticker', NULL, '1106366167788044450', '122155380120748034', 0, 0),
 | 
				
			||||||
 | 
					('$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04', 'm.room.message', 'm.text', '1144865310588014633', '687028734322147344', 0, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
INSERT INTO file (discord_url, mxc_url) VALUES
 | 
					INSERT INTO file (discord_url, mxc_url) VALUES
 | 
				
			||||||
('https://cdn.discordapp.com/attachments/497161332244742154/1124628646431297546/image.png', 'mxc://cadence.moe/qXoZktDqNtEGuOCZEADAMvhM'),
 | 
					('https://cdn.discordapp.com/attachments/497161332244742154/1124628646431297546/image.png', 'mxc://cadence.moe/qXoZktDqNtEGuOCZEADAMvhM'),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,8 @@ const {sync, discord, db} = passthrough
 | 
				
			||||||
const channelWebhook = sync.require("./channel-webhook")
 | 
					const channelWebhook = sync.require("./channel-webhook")
 | 
				
			||||||
/** @type {import("../converters/event-to-message")} */
 | 
					/** @type {import("../converters/event-to-message")} */
 | 
				
			||||||
const eventToMessage = sync.require("../converters/event-to-message")
 | 
					const eventToMessage = sync.require("../converters/event-to-message")
 | 
				
			||||||
 | 
					/** @type {import("../../matrix/api")}) */
 | 
				
			||||||
 | 
					const api = sync.require("../../matrix/api")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @param {import("../../types").Event.Outer<any>} event */
 | 
					/** @param {import("../../types").Event.Outer<any>} event */
 | 
				
			||||||
async function sendEvent(event) {
 | 
					async function sendEvent(event) {
 | 
				
			||||||
| 
						 | 
					@ -20,10 +22,14 @@ async function sendEvent(event) {
 | 
				
			||||||
		threadID = channelID
 | 
							threadID = channelID
 | 
				
			||||||
		channelID = row.thread_parent // it's the thread's parent... get with the times...
 | 
							channelID = row.thread_parent // it's the thread's parent... get with the times...
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// @ts-ignore
 | 
				
			||||||
 | 
						const guildID = discord.channels.get(channelID).guild_id
 | 
				
			||||||
 | 
						const guild = discord.guilds.get(guildID)
 | 
				
			||||||
 | 
						assert(guild)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// no need to sync the matrix member to the other side. but if I did need to, this is where I'd do it
 | 
						// 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 = eventToMessage.eventToMessage(event)
 | 
						const messages = await eventToMessage.eventToMessage(event, guild, {api})
 | 
				
			||||||
	assert(Array.isArray(messages)) // sanity
 | 
						assert(Array.isArray(messages)) // sanity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** @type {DiscordTypes.APIMessage[]} */
 | 
						/** @type {DiscordTypes.APIMessage[]} */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,8 @@ const turndownService = new TurndownService({
 | 
				
			||||||
	codeBlockStyle: "fenced"
 | 
						codeBlockStyle: "fenced"
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					turndownService.remove("mx-reply")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
turndownService.addRule("strikethrough", {
 | 
					turndownService.addRule("strikethrough", {
 | 
				
			||||||
	filter: ["del", "s", "strike"],
 | 
						filter: ["del", "s", "strike"],
 | 
				
			||||||
	replacement: function (content) {
 | 
						replacement: function (content) {
 | 
				
			||||||
| 
						 | 
					@ -69,13 +71,16 @@ turndownService.addRule("fencedCodeBlock", {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @param {Ty.Event.Outer<Ty.Event.M_Room_Message>} event
 | 
					 * @param {Ty.Event.Outer<Ty.Event.M_Room_Message>} event
 | 
				
			||||||
 | 
					 * @param {import("discord-api-types/v10").APIGuild} guild
 | 
				
			||||||
 | 
					 * @param {{api: import("../../matrix/api")}} di simple-as-nails dependency injection for the matrix API
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function eventToMessage(event) {
 | 
					async function eventToMessage(event, guild, di) {
 | 
				
			||||||
	/** @type {(DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer}[]})[]} */
 | 
						/** @type {(DiscordTypes.RESTPostAPIWebhookWithTokenJSONBody & {files?: {name: string, file: Buffer}[]})[]} */
 | 
				
			||||||
	let messages = []
 | 
						let messages = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let displayName = event.sender
 | 
						let displayName = event.sender
 | 
				
			||||||
	let avatarURL = undefined
 | 
						let avatarURL = undefined
 | 
				
			||||||
 | 
						let replyLine = ""
 | 
				
			||||||
	const match = event.sender.match(/^@(.*?):/)
 | 
						const match = event.sender.match(/^@(.*?):/)
 | 
				
			||||||
	if (match) {
 | 
						if (match) {
 | 
				
			||||||
		displayName = match[1]
 | 
							displayName = match[1]
 | 
				
			||||||
| 
						 | 
					@ -95,7 +100,33 @@ function eventToMessage(event) {
 | 
				
			||||||
		// input = input.replace(/ /g, " ")
 | 
							// input = input.replace(/ /g, " ")
 | 
				
			||||||
		// There is also a corresponding test to uncomment, named "event2message: whitespace is retained"
 | 
							// There is also a corresponding test to uncomment, named "event2message: whitespace is retained"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Element adds a bunch of <br> before </blockquote> but doesn't render them. I can't figure out how this works, so let's just delete those.
 | 
							// Handling replies. We'll look up the data of the replied-to event from the Matrix homeserver.
 | 
				
			||||||
 | 
							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
 | 
				
			||||||
 | 
								const row = db.prepare("SELECT channel_id, message_id FROM event_message WHERE event_id = ? ORDER BY part").get(repliedToEventId)
 | 
				
			||||||
 | 
								if (row) {
 | 
				
			||||||
 | 
									replyLine = `<:L1:1144820033948762203><:L2:1144820084079087647>https://discord.com/channels/${guild.id}/${row.channel_id}/${row.message_id} `
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									replyLine = `<:L1:1144820033948762203><:L2:1144820084079087647>`
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								const sender = repliedToEvent.sender
 | 
				
			||||||
 | 
								const senderName = sender.match(/@([^:]*)/)?.[1] || sender
 | 
				
			||||||
 | 
								const authorID = db.prepare("SELECT discord_id FROM sim WHERE mxid = ?").pluck().get(repliedToEvent.sender)
 | 
				
			||||||
 | 
								if (authorID) {
 | 
				
			||||||
 | 
									replyLine += `<@${authorID}>: `
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									replyLine += `Ⓜ️**${senderName}**: `
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								const repliedToContent = repliedToEvent.content.formatted_body || repliedToEvent.content.body
 | 
				
			||||||
 | 
								const contentPreviewChunks = chunk(repliedToContent.replace(/.*<\/mx-reply>/, "").replace(/(?:\n|<br>)+/g, " ").replace(/<[^>]+>/g, ""), 24)
 | 
				
			||||||
 | 
								const contentPreview = contentPreviewChunks.length > 1 ? contentPreviewChunks[0] + "..." : contentPreviewChunks[0]
 | 
				
			||||||
 | 
								replyLine += contentPreview + "\n"
 | 
				
			||||||
 | 
							})()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Element adds a bunch of <br> before </blockquote> but doesn't render them. I can't figure out how this even works in the browser, so let's just delete those.
 | 
				
			||||||
		input = input.replace(/(?:\n|<br ?\/?>\s*)*<\/blockquote>/g, "</blockquote>")
 | 
							input = input.replace(/(?:\n|<br ?\/?>\s*)*<\/blockquote>/g, "</blockquote>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// The matrix spec hasn't decided whether \n counts as a newline or not, but I'm going to count it, because if it's in the data it's there for a reason.
 | 
							// The matrix spec hasn't decided whether \n counts as a newline or not, but I'm going to count it, because if it's in the data it's there for a reason.
 | 
				
			||||||
| 
						 | 
					@ -127,6 +158,8 @@ function eventToMessage(event) {
 | 
				
			||||||
		content = content.replace(/([*_~`#])/g, `\\$1`)
 | 
							content = content.replace(/([*_~`#])/g, `\\$1`)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						content = replyLine + content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Split into 2000 character chunks
 | 
						// Split into 2000 character chunks
 | 
				
			||||||
	const chunks = chunk(content, 2000)
 | 
						const chunks = chunk(content, 2000)
 | 
				
			||||||
	messages = messages.concat(chunks.map(content => ({
 | 
						messages = messages.concat(chunks.map(content => ({
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,18 +1,42 @@
 | 
				
			||||||
// @ts-check
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const {test} = require("supertape")
 | 
					const {test} = require("supertape")
 | 
				
			||||||
const {eventToMessage} = require("./event-to-message")
 | 
					const {eventToMessage} = require("./event-to-message")
 | 
				
			||||||
const data = require("../../test/data")
 | 
					const data = require("../../test/data")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {string} roomID
 | 
				
			||||||
 | 
					 * @param {string} eventID
 | 
				
			||||||
 | 
					 * @returns {(roomID: string, eventID: string) => Promise<Ty.Event.Outer<Ty.Event.M_Room_Message>>}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function mockGetEvent(t, roomID_in, eventID_in, outer) {
 | 
				
			||||||
 | 
						return async function(roomID, eventID) {
 | 
				
			||||||
 | 
							t.equal(roomID, roomID_in)
 | 
				
			||||||
 | 
							t.equal(eventID, eventID_in)
 | 
				
			||||||
 | 
							return new Promise(resolve => {
 | 
				
			||||||
 | 
								setTimeout(() => {
 | 
				
			||||||
 | 
									resolve({
 | 
				
			||||||
 | 
										event_id: eventID_in,
 | 
				
			||||||
 | 
										room_id: roomID_in,
 | 
				
			||||||
 | 
										origin_server_ts: 1680000000000,
 | 
				
			||||||
 | 
										unsigned: {
 | 
				
			||||||
 | 
											age: 2245,
 | 
				
			||||||
 | 
											transaction_id: "$local.whatever"
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										...outer
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function sameFirstContentAndWhitespace(t, a, b) {
 | 
					function sameFirstContentAndWhitespace(t, a, b) {
 | 
				
			||||||
	const a2 = JSON.stringify(a[0].content)
 | 
						const a2 = JSON.stringify(a[0].content)
 | 
				
			||||||
	const b2 = JSON.stringify(b[0].content)
 | 
						const b2 = JSON.stringify(b[0].content)
 | 
				
			||||||
	t.equal(a2, b2)
 | 
						t.equal(a2, b2)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: body is used when there is no formatted_body", t => {
 | 
					test("event2message: body is used when there is no formatted_body", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				body: "testing plaintext",
 | 
									body: "testing plaintext",
 | 
				
			||||||
				msgtype: "m.text"
 | 
									msgtype: "m.text"
 | 
				
			||||||
| 
						 | 
					@ -34,9 +58,9 @@ test("event2message: body is used when there is no formatted_body", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: any markdown in body is escaped", t => {
 | 
					test("event2message: any markdown in body is escaped", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				body: "testing **special** ~~things~~ which _should_ *not* `trigger` @any <effects>",
 | 
									body: "testing **special** ~~things~~ which _should_ *not* `trigger` @any <effects>",
 | 
				
			||||||
				msgtype: "m.text"
 | 
									msgtype: "m.text"
 | 
				
			||||||
| 
						 | 
					@ -58,9 +82,9 @@ test("event2message: any markdown in body is escaped", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: basic html is converted to markdown", t => {
 | 
					test("event2message: basic html is converted to markdown", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				msgtype: "m.text",
 | 
									msgtype: "m.text",
 | 
				
			||||||
				body: "wrong body",
 | 
									body: "wrong body",
 | 
				
			||||||
| 
						 | 
					@ -84,9 +108,9 @@ test("event2message: basic html is converted to markdown", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: markdown syntax is escaped", t => {
 | 
					test("event2message: markdown syntax is escaped", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				msgtype: "m.text",
 | 
									msgtype: "m.text",
 | 
				
			||||||
				body: "wrong body",
 | 
									body: "wrong body",
 | 
				
			||||||
| 
						 | 
					@ -110,9 +134,9 @@ test("event2message: markdown syntax is escaped", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: html lines are bridged correctly", t => {
 | 
					test("event2message: html lines are bridged correctly", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				msgtype: "m.text",
 | 
									msgtype: "m.text",
 | 
				
			||||||
				body: "wrong body",
 | 
									body: "wrong body",
 | 
				
			||||||
| 
						 | 
					@ -136,9 +160,9 @@ test("event2message: html lines are bridged correctly", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*test("event2message: whitespace is retained", t => {
 | 
					/*test("event2message: whitespace is retained", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				msgtype: "m.text",
 | 
									msgtype: "m.text",
 | 
				
			||||||
				body: "wrong body",
 | 
									body: "wrong body",
 | 
				
			||||||
| 
						 | 
					@ -162,10 +186,10 @@ test("event2message: html lines are bridged correctly", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})*/
 | 
					})*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: whitespace is collapsed", t => {
 | 
					test("event2message: whitespace is collapsed", async t => {
 | 
				
			||||||
	sameFirstContentAndWhitespace(
 | 
						sameFirstContentAndWhitespace(
 | 
				
			||||||
		t,
 | 
							t,
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				msgtype: "m.text",
 | 
									msgtype: "m.text",
 | 
				
			||||||
				body: "wrong body",
 | 
									body: "wrong body",
 | 
				
			||||||
| 
						 | 
					@ -189,10 +213,10 @@ test("event2message: whitespace is collapsed", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: lists are bridged correctly", t => {
 | 
					test("event2message: lists are bridged correctly", async t => {
 | 
				
			||||||
	sameFirstContentAndWhitespace(
 | 
						sameFirstContentAndWhitespace(
 | 
				
			||||||
		t,
 | 
							t,
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			"type": "m.room.message",
 | 
								"type": "m.room.message",
 | 
				
			||||||
			"sender": "@cadence:cadence.moe",
 | 
								"sender": "@cadence:cadence.moe",
 | 
				
			||||||
			"content": {
 | 
								"content": {
 | 
				
			||||||
| 
						 | 
					@ -217,9 +241,9 @@ test("event2message: lists are bridged correctly", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: long messages are split", t => {
 | 
					test("event2message: long messages are split", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				body: ("a".repeat(130) + " ").repeat(19),
 | 
									body: ("a".repeat(130) + " ").repeat(19),
 | 
				
			||||||
				msgtype: "m.text"
 | 
									msgtype: "m.text"
 | 
				
			||||||
| 
						 | 
					@ -245,9 +269,9 @@ test("event2message: long messages are split", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: code blocks work", t => {
 | 
					test("event2message: code blocks work", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				msgtype: "m.text",
 | 
									msgtype: "m.text",
 | 
				
			||||||
				body: "wrong body",
 | 
									body: "wrong body",
 | 
				
			||||||
| 
						 | 
					@ -271,9 +295,9 @@ test("event2message: code blocks work", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: code block contents are formatted correctly and not escaped", t => {
 | 
					test("event2message: code block contents are formatted correctly and not escaped", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			"type": "m.room.message",
 | 
								"type": "m.room.message",
 | 
				
			||||||
			"sender": "@cadence:cadence.moe",
 | 
								"sender": "@cadence:cadence.moe",
 | 
				
			||||||
			"content": {
 | 
								"content": {
 | 
				
			||||||
| 
						 | 
					@ -298,9 +322,9 @@ test("event2message: code block contents are formatted correctly and not escaped
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: quotes have an appropriate amount of whitespace", t => {
 | 
					test("event2message: quotes have an appropriate amount of whitespace", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				msgtype: "m.text",
 | 
									msgtype: "m.text",
 | 
				
			||||||
				body: "wrong body",
 | 
									body: "wrong body",
 | 
				
			||||||
| 
						 | 
					@ -324,9 +348,9 @@ test("event2message: quotes have an appropriate amount of whitespace", t => {
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test("event2message: m.emote markdown syntax is escaped", t => {
 | 
					test("event2message: m.emote markdown syntax is escaped", async t => {
 | 
				
			||||||
	t.deepEqual(
 | 
						t.deepEqual(
 | 
				
			||||||
		eventToMessage({
 | 
							await eventToMessage({
 | 
				
			||||||
			content: {
 | 
								content: {
 | 
				
			||||||
				msgtype: "m.emote",
 | 
									msgtype: "m.emote",
 | 
				
			||||||
				body: "wrong body",
 | 
									body: "wrong body",
 | 
				
			||||||
| 
						 | 
					@ -349,3 +373,136 @@ test("event2message: m.emote markdown syntax is escaped", t => {
 | 
				
			||||||
		}]
 | 
							}]
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("event2message: rich reply to a sim user", async t => {
 | 
				
			||||||
 | 
						t.deepEqual(
 | 
				
			||||||
 | 
							await eventToMessage({
 | 
				
			||||||
 | 
								"type": "m.room.message",
 | 
				
			||||||
 | 
								"sender": "@cadence:cadence.moe",
 | 
				
			||||||
 | 
								"content": {
 | 
				
			||||||
 | 
									"msgtype": "m.text",
 | 
				
			||||||
 | 
									"body": "> <@_ooye_kyuugryphon:cadence.moe> Slow news day.\n\nTesting this reply, ignore",
 | 
				
			||||||
 | 
									"format": "org.matrix.custom.html",
 | 
				
			||||||
 | 
									"formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!fGgIymcYWOqjbSRUdV:cadence.moe/$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04?via=cadence.moe&via=feather.onl\">In reply to</a> <a href=\"https://matrix.to/#/@_ooye_kyuugryphon:cadence.moe\">@_ooye_kyuugryphon:cadence.moe</a><br>Slow news day.</blockquote></mx-reply>Testing this reply, ignore",
 | 
				
			||||||
 | 
									"m.relates_to": {
 | 
				
			||||||
 | 
										"m.in_reply_to": {
 | 
				
			||||||
 | 
											"event_id": "$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04"
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								"origin_server_ts": 1693029683016,
 | 
				
			||||||
 | 
								"unsigned": {
 | 
				
			||||||
 | 
									"age": 91,
 | 
				
			||||||
 | 
									"transaction_id": "m1693029682894.510"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								"event_id": "$v_Gtr-bzv9IVlSLBO5DstzwmiDd-GSFaNfHX66IupV8",
 | 
				
			||||||
 | 
								"room_id": "!fGgIymcYWOqjbSRUdV:cadence.moe"
 | 
				
			||||||
 | 
							}, data.guild.general, {
 | 
				
			||||||
 | 
								api: {
 | 
				
			||||||
 | 
									getEvent: mockGetEvent(t, "!fGgIymcYWOqjbSRUdV:cadence.moe", "$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04", {
 | 
				
			||||||
 | 
										type: "m.room.message",
 | 
				
			||||||
 | 
										content: {
 | 
				
			||||||
 | 
											msgtype: "m.text",
 | 
				
			||||||
 | 
											body: "Slow news day."
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										sender: "@_ooye_kyuugryphon:cadence.moe"
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
							[{
 | 
				
			||||||
 | 
								username: "cadence",
 | 
				
			||||||
 | 
								content: "<:L1:1144820033948762203><:L2:1144820084079087647>https://discord.com/channels/112760669178241024/687028734322147344/1144865310588014633 <@111604486476181504>: Slow news day.\nTesting this reply, ignore",
 | 
				
			||||||
 | 
								avatar_url: undefined
 | 
				
			||||||
 | 
							}]
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("event2message: rich reply to a matrix user's long message with formatting", async t => {
 | 
				
			||||||
 | 
						t.deepEqual(
 | 
				
			||||||
 | 
							await eventToMessage({
 | 
				
			||||||
 | 
								"type": "m.room.message",
 | 
				
			||||||
 | 
								"sender": "@cadence:cadence.moe",
 | 
				
			||||||
 | 
								"content": {
 | 
				
			||||||
 | 
								  "msgtype": "m.text",
 | 
				
			||||||
 | 
								  "body": "> <@cadence:cadence.moe> ```\n> i should have a little happy test\n> ```\n> * list **bold** _em_ ~~strike~~\n> # heading 1\n> ## heading 2\n> ### heading 3\n> https://cadence.moe\n> [legit website](https://cadence.moe)\n\nno you can't!!!",
 | 
				
			||||||
 | 
								  "format": "org.matrix.custom.html",
 | 
				
			||||||
 | 
								  "formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!fGgIymcYWOqjbSRUdV:cadence.moe/$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04?via=cadence.moe&via=feather.onl\">In reply to</a> <a href=\"https://matrix.to/#/@cadence:cadence.moe\">@cadence:cadence.moe</a><br><pre><code>i should have a little happy test\n</code></pre>\n<ul>\n<li>list <strong>bold</strong> <em>em</em> ~~strike~~</li>\n</ul>\n<h1>heading 1</h1>\n<h2>heading 2</h2>\n<h3>heading 3</h3>\n<p>https://cadence.moe<br /><a href=\"https://cadence.moe\">legit website</a></p>\n</blockquote></mx-reply><strong>no you can't!!!</strong>",
 | 
				
			||||||
 | 
								  "m.relates_to": {
 | 
				
			||||||
 | 
									 "m.in_reply_to": {
 | 
				
			||||||
 | 
										"event_id": "$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04"
 | 
				
			||||||
 | 
									 }
 | 
				
			||||||
 | 
								  }
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								"origin_server_ts": 1693037401693,
 | 
				
			||||||
 | 
								"unsigned": {
 | 
				
			||||||
 | 
								  "age": 381,
 | 
				
			||||||
 | 
								  "transaction_id": "m1693037401592.521"
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								"event_id": "$v_Gtr-bzv9IVlSLBO5DstzwmiDd-GSFaNfHX66IupV8",
 | 
				
			||||||
 | 
								"room_id": "!fGgIymcYWOqjbSRUdV:cadence.moe"
 | 
				
			||||||
 | 
							 }, data.guild.general, {
 | 
				
			||||||
 | 
								api: {
 | 
				
			||||||
 | 
									getEvent: mockGetEvent(t, "!fGgIymcYWOqjbSRUdV:cadence.moe", "$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04", {
 | 
				
			||||||
 | 
										"type": "m.room.message",
 | 
				
			||||||
 | 
										"sender": "@cadence:cadence.moe",
 | 
				
			||||||
 | 
										"content": {
 | 
				
			||||||
 | 
											"msgtype": "m.text",
 | 
				
			||||||
 | 
											"body": "```\ni should have a little happy test\n```\n* list **bold** _em_ ~~strike~~\n# heading 1\n## heading 2\n### heading 3\nhttps://cadence.moe\n[legit website](https://cadence.moe)",
 | 
				
			||||||
 | 
											"format": "org.matrix.custom.html",
 | 
				
			||||||
 | 
											"formatted_body": "<pre><code>i should have a little happy test\n</code></pre>\n<ul>\n<li>list <strong>bold</strong> <em>em</em> ~~strike~~</li>\n</ul>\n<h1>heading 1</h1>\n<h2>heading 2</h2>\n<h3>heading 3</h3>\n<p>https://cadence.moe<br><a href=\"https://cadence.moe\">legit website</a></p>\n"
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
							[{
 | 
				
			||||||
 | 
								username: "cadence",
 | 
				
			||||||
 | 
								content: "<:L1:1144820033948762203><:L2:1144820084079087647>https://discord.com/channels/112760669178241024/687028734322147344/1144865310588014633 Ⓜ️**cadence**: i should have a little...\n**no you can't!!!**",
 | 
				
			||||||
 | 
								avatar_url: undefined
 | 
				
			||||||
 | 
							}]
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test("event2message: with layered rich replies, the preview should only be the real text", async t => {
 | 
				
			||||||
 | 
						t.deepEqual(
 | 
				
			||||||
 | 
							await eventToMessage({
 | 
				
			||||||
 | 
								type: "m.room.message",
 | 
				
			||||||
 | 
								sender: "@cadence:cadence.moe",
 | 
				
			||||||
 | 
								content: {
 | 
				
			||||||
 | 
									msgtype: "m.text",
 | 
				
			||||||
 | 
									body: "> <@cadence:cadence.moe> two\n\nthree",
 | 
				
			||||||
 | 
									format: "org.matrix.custom.html",
 | 
				
			||||||
 | 
									formatted_body: "<mx-reply><blockquote><a href=\"https://matrix.to/#/!PnyBKvUBOhjuCucEfk:cadence.moe/$f-noT-d-Eo_Xgpc05Ww89ErUXku4NwKWYGHLzWKo1kU?via=cadence.moe\">In reply to</a> <a href=\"https://matrix.to/#/@cadence:cadence.moe\">@cadence:cadence.moe</a><br>two</blockquote></mx-reply>three",
 | 
				
			||||||
 | 
									"m.relates_to": {
 | 
				
			||||||
 | 
										"m.in_reply_to": {
 | 
				
			||||||
 | 
											event_id: "$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04"
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								event_id: "$v_Gtr-bzv9IVlSLBO5DstzwmiDd-GSFaNfHX66IupV8",
 | 
				
			||||||
 | 
								room_id: "!fGgIymcYWOqjbSRUdV:cadence.moe"
 | 
				
			||||||
 | 
							 }, data.guild.general, {
 | 
				
			||||||
 | 
								api: {
 | 
				
			||||||
 | 
									getEvent: mockGetEvent(t, "!fGgIymcYWOqjbSRUdV:cadence.moe", "$Fxy8SMoJuTduwReVkHZ1uHif9EuvNx36Hg79cltiA04", {
 | 
				
			||||||
 | 
										"type": "m.room.message",
 | 
				
			||||||
 | 
										"sender": "@cadence:cadence.moe",
 | 
				
			||||||
 | 
										"content": {
 | 
				
			||||||
 | 
											"msgtype": "m.text",
 | 
				
			||||||
 | 
											"body": "> <@cadence:cadence.moe> one\n\ntwo",
 | 
				
			||||||
 | 
											"format": "org.matrix.custom.html",
 | 
				
			||||||
 | 
											"formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!PnyBKvUBOhjuCucEfk:cadence.moe/$5UtboIC30EFlAYD_Oh0pSYVW8JqOp6GsDIJZHtT0Wls?via=cadence.moe\">In reply to</a> <a href=\"https://matrix.to/#/@cadence:cadence.moe\">@cadence:cadence.moe</a><br>one</blockquote></mx-reply>two",
 | 
				
			||||||
 | 
											"m.relates_to": {
 | 
				
			||||||
 | 
												"m.in_reply_to": {
 | 
				
			||||||
 | 
													"event_id": "$5UtboIC30EFlAYD_Oh0pSYVW8JqOp6GsDIJZHtT0Wls"
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
							[{
 | 
				
			||||||
 | 
								username: "cadence",
 | 
				
			||||||
 | 
								content: "<:L1:1144820033948762203><:L2:1144820084079087647>https://discord.com/channels/112760669178241024/687028734322147344/1144865310588014633 Ⓜ️**cadence**: two\nthree",
 | 
				
			||||||
 | 
								avatar_url: undefined
 | 
				
			||||||
 | 
							}]
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue