Improve test coverage
This commit is contained in:
		| @@ -257,6 +257,15 @@ async function messageToEvent(message, guild, options = {}, di) { | ||||
| 		if (match) { | ||||
| 			const row = from("event_message").join("message_channel", "message_id").join("channel_room", "channel_id").select("event_id", "room_id", "source").and("WHERE message_id = ? AND part = 0").get(match[1]) | ||||
| 			if (row) { | ||||
| 				/* | ||||
| 					we generate a partial referenced_message based on what PK provided. we don't need everything, since this will only be used for further message-to-event converting. | ||||
| 					the following properties are necessary: | ||||
| 					- content: used for generating the reply fallback | ||||
| 				*/ | ||||
| 				// @ts-ignore | ||||
| 				message.referenced_message = { | ||||
| 					content: message.embeds[0].description.replace(/^.*?\)\*\*\s*/, "") | ||||
| 				} | ||||
| 				message.embeds.shift() | ||||
| 				repliedToEventRow = row | ||||
| 			} | ||||
|   | ||||
							
								
								
									
										64
									
								
								d2m/converters/message-to-event.pk.test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								d2m/converters/message-to-event.pk.test.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| const {test} = require("supertape") | ||||
| const {messageToEvent} = require("./message-to-event") | ||||
| const data = require("../../test/data") | ||||
| const Ty = require("../../types") | ||||
|  | ||||
| /** | ||||
|  * @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 | ||||
| 				}) | ||||
| 			}) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| test("message2event: pk reply is converted to native matrix reply", async t => { | ||||
| 	const events = await messageToEvent(data.pk_message.pk_reply, {}, {}, { | ||||
| 		api: { | ||||
| 			getEvent: mockGetEvent(t, "!TqlyQmifxGUggEmdBN:cadence.moe", "$NB6nPgO2tfXyIwwDSF0Ga0BUrsgX1S-0Xl-jAvI8ucU", { | ||||
| 				type: "m.room.message", | ||||
| 				sender: "@cadence:cadence.moe", | ||||
| 				content: { | ||||
| 					msgtype: "m.text", | ||||
| 					body: "now for my next experiment:" | ||||
| 				} | ||||
| 			}) | ||||
| 		} | ||||
| 	}) | ||||
| 	t.deepEqual(events, [{ | ||||
| 		$type: "m.room.message", | ||||
| 		"m.mentions": { | ||||
| 			user_ids: [ | ||||
| 				"@cadence:cadence.moe" | ||||
| 			] | ||||
| 		}, | ||||
| 		msgtype: "m.text", | ||||
| 		body: "> cadence: now for my next experiment:\n\nthis is a reply", | ||||
| 		format: "org.matrix.custom.html", | ||||
| 		formatted_body: '<mx-reply><blockquote><a href="https://matrix.to/#/!TqlyQmifxGUggEmdBN:cadence.moe/$NB6nPgO2tfXyIwwDSF0Ga0BUrsgX1S-0Xl-jAvI8ucU">In reply to</a> <a href="https://matrix.to/#/@cadence:cadence.moe">cadence</a><br>' | ||||
| 			+ "now for my next experiment:</blockquote></mx-reply>" | ||||
| 			+ "this is a reply", | ||||
| 		"m.relates_to": { | ||||
| 			"m.in_reply_to": { | ||||
| 				event_id: "$NB6nPgO2tfXyIwwDSF0Ga0BUrsgX1S-0Xl-jAvI8ucU" | ||||
| 			} | ||||
| 		} | ||||
| 	}]) | ||||
| }) | ||||
| @@ -397,6 +397,46 @@ test("message2event: reply with a video", async t => { | ||||
| 	}]) | ||||
| }) | ||||
|  | ||||
| test("message2event: voice message", async t => { | ||||
| 	const events = await messageToEvent(data.message.voice_message) | ||||
| 	t.deepEqual(events, [{ | ||||
| 		$type: "m.room.message", | ||||
|       body: "voice-message.ogg", | ||||
|       external_url: "https://cdn.discordapp.com/attachments/1099031887500034088/1112476845502365786/voice-message.ogg?ex=65c92d4c&is=65b6b84c&hm=0654bab5027474cbe23875954fa117cf44d8914c144cd151879590fa1baf8b1c&", | ||||
|       filename: "voice-message.ogg", | ||||
|       info: { | ||||
|         duration: 3960.0000381469727, | ||||
|         mimetype: "audio/ogg", | ||||
|         size: 10584, | ||||
| 		}, | ||||
|       "m.mentions": {}, | ||||
|       msgtype: "m.audio", | ||||
|       url: "mxc://cadence.moe/MRRPDggXQMYkrUjTpxQbmcxB" | ||||
| 	}]) | ||||
| }) | ||||
|  | ||||
| test("message2event: misc file", async t => { | ||||
| 	const events = await messageToEvent(data.message.misc_file) | ||||
| 	t.deepEqual(events, [{ | ||||
| 		$type: "m.room.message", | ||||
| 		msgtype: "m.text", | ||||
| 		body: "final final final revised draft", | ||||
| 		"m.mentions": {} | ||||
| 	}, { | ||||
| 		$type: "m.room.message", | ||||
|       body: "the.yml", | ||||
|       external_url: "https://cdn.discordapp.com/attachments/122155380120748034/1174514575220158545/the.yml?ex=65cd6270&is=65baed70&hm=8c5f1b571784e3c7f99628492298815884e351ae0dc7c2ae40dd22d97caf27d9&", | ||||
|       filename: "the.yml", | ||||
| 		info: { | ||||
| 			mimetype: "text/plain; charset=utf-8", | ||||
| 			size: 2274 | ||||
| 		}, | ||||
|       "m.mentions": {}, | ||||
|       msgtype: "m.file", | ||||
|       url: "mxc://cadence.moe/HnQIYQmmlIKwOQsbFsIGpzPP" | ||||
| 	}]) | ||||
| }) | ||||
|  | ||||
| test("message2event: simple reply in thread to a matrix user's reply", async t => { | ||||
| 	const events = await messageToEvent(data.message.simple_reply_to_reply_in_thread, data.guild.general, {}, { | ||||
| 		api: { | ||||
|   | ||||
| @@ -16,7 +16,6 @@ async function migrate(db) { | ||||
| 	let migrationRan = false | ||||
|  | ||||
| 	for (const filename of files) { | ||||
| 		/* c8 ignore next - we can't unit test this, but it's run on every real world bridge startup */ | ||||
| 		if (progress >= filename) continue | ||||
| 		console.log(`Applying database migration ${filename}`) | ||||
| 		if (filename.endsWith(".sql")) { | ||||
|   | ||||
| @@ -39,6 +39,7 @@ async function runSingleTest(t, url, totalSize) { | ||||
| 		res.body.emit("end") | ||||
| 	}) | ||||
| 	t.equal(result.subarray(1, 4).toString("ascii"), "PNG", `result was not a PNG file: ${result.toString("base64")}`) | ||||
| 	/* c8 ignore next 5 */ | ||||
| 	if (meter.bytes < totalSize / 4) { // should download less than 25% of each file | ||||
| 		t.pass("intentionally read partial file") | ||||
| 	} else { | ||||
|   | ||||
| @@ -5,6 +5,7 @@ const DiscordTypes = require("discord-api-types/v10") | ||||
| const {Readable} = require("stream") | ||||
| const chunk = require("chunk-text") | ||||
| const TurndownService = require("turndown") | ||||
| const domino = require("domino") | ||||
| const assert = require("assert").strict | ||||
| const entities = require("entities") | ||||
|  | ||||
| @@ -38,7 +39,7 @@ const turndownService = new TurndownService({ | ||||
| 	hr: "----", | ||||
| 	headingStyle: "atx", | ||||
| 	preformattedCode: true, | ||||
| 	codeBlockStyle: "fenced", | ||||
| 	codeBlockStyle: "fenced" | ||||
| }) | ||||
|  | ||||
| /** | ||||
| @@ -339,6 +340,33 @@ async function handleRoomOrMessageLinks(input, di) { | ||||
| 	return input | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} content | ||||
|  * @param {DiscordTypes.APIGuild} guild | ||||
|  * @param {{api: import("../../matrix/api"), snow: import("snowtransfer").SnowTransfer, fetch: import("node-fetch")["default"]}} di | ||||
|  */ | ||||
| async function checkWrittenMentions(content, guild, di) { | ||||
| 	let writtenMentionMatch = content.match(/(?:^|[^"[<>/A-Za-z0-9])@([A-Za-z][A-Za-z0-9._\[\]\(\)-]+):?/d) // /d flag for indices requires node.js 16+ | ||||
| 	if (writtenMentionMatch) { | ||||
| 		const results = await di.snow.guild.searchGuildMembers(guild.id, {query: writtenMentionMatch[1]}) | ||||
| 		if (results[0]) { | ||||
| 			assert(results[0].user) | ||||
| 			return { | ||||
| 				// @ts-ignore - typescript doesn't know about indices yet | ||||
| 				content: content.slice(0, writtenMentionMatch.indices[1][0]-1) + `<@${results[0].user.id}>` + content.slice(writtenMentionMatch.indices[1][1]), | ||||
| 				ensureJoined: results[0].user | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const attachmentEmojis = new Map([ | ||||
| 	["m.image", "🖼️"], | ||||
| 	["m.video", "🎞️"], | ||||
| 	["m.audio", "🎶"], | ||||
| 	["m.file", "📄"] | ||||
| ]) | ||||
|  | ||||
| /** | ||||
|  * @param {Ty.Event.Outer_M_Room_Message | Ty.Event.Outer_M_Room_Message_File | Ty.Event.Outer_M_Sticker | Ty.Event.Outer_M_Room_Message_Encrypted_File} event | ||||
|  * @param {import("discord-api-types/v10").APIGuild} guild | ||||
| @@ -380,12 +408,10 @@ async function eventToMessage(event, guild, di) { | ||||
| 		// 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 () => { | ||||
| 			if (!event.content["m.new_content"]) return | ||||
| 			// Check if there is an edit | ||||
| 			const relatesTo = event.content["m.relates_to"] | ||||
| 			if (!relatesTo) return | ||||
| 			if (!event.content["m.new_content"] || !relatesTo || relatesTo.rel_type !== "m.replace") 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 | ||||
| 			messageIDsToEdit = select("event_message", "message_id", {event_id: originalEventId}, "ORDER BY part").pluck().all() | ||||
| @@ -480,12 +506,7 @@ async function eventToMessage(event, guild, di) { | ||||
| 				repliedToEvent.content = repliedToEvent.content["m.new_content"] | ||||
| 			} | ||||
| 			let contentPreview | ||||
| 			const fileReplyContentAlternative = | ||||
| 				( repliedToEvent.content.msgtype === "m.image" ? "🖼️" | ||||
| 				: repliedToEvent.content.msgtype === "m.video" ? "🎞️" | ||||
| 				: repliedToEvent.content.msgtype === "m.audio" ? "🎶" | ||||
| 				: repliedToEvent.content.msgtype === "m.file" ? "📄" | ||||
| 				: null) | ||||
| 			const fileReplyContentAlternative = attachmentEmojis.get(repliedToEvent.content.msgtype) | ||||
| 			if (fileReplyContentAlternative) { | ||||
| 				contentPreview = " " + fileReplyContentAlternative | ||||
| 			} else { | ||||
| @@ -574,8 +595,35 @@ async function eventToMessage(event, guild, di) { | ||||
| 				last = match.index | ||||
| 			} | ||||
|  | ||||
| 			// Handling written @mentions: we need to look for candidate Discord members to join to the room | ||||
| 			// This shouldn't apply to code blocks, links, or inside attributes. So editing the HTML tree instead of regular expressions is a sensible choice here. | ||||
| 			// We're using the domino parser because Turndown uses the same and can reuse this tree. | ||||
| 			const doc = domino.createDocument( | ||||
| 				// DOM parsers arrange elements in the <head> and <body>. Wrapping in a custom element ensures elements are reliably arranged in a single element. | ||||
| 				'<x-turndown id="turndown-root">' + input + '</x-turndown>' | ||||
| 			); | ||||
| 			const root = doc.getElementById("turndown-root"); | ||||
| 			async function forEachNode(node) { | ||||
| 				for (; node; node = node.nextSibling) { | ||||
| 					if (node.nodeType === 3 && node.nodeValue.includes("@")) { | ||||
| 						const result = await checkWrittenMentions(node.nodeValue, guild, di) | ||||
| 						if (result) { | ||||
| 							node.nodeValue = result.content | ||||
| 							ensureJoined.push(result.ensureJoined) | ||||
| 						} | ||||
| 					} | ||||
| 					if (node.nodeType === 1 && ["CODE", "PRE", "A"].includes(node.tagName)) { | ||||
| 						// don't recurse into code or links | ||||
| 					} else { | ||||
| 						// do recurse into everything else | ||||
| 						await forEachNode(node.firstChild) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			await forEachNode(root) | ||||
|  | ||||
| 			// @ts-ignore bad type from turndown | ||||
| 			content = turndownService.turndown(input) | ||||
| 			content = turndownService.turndown(root) | ||||
|  | ||||
| 			// It's designed for commonmark, we need to replace the space-space-newline with just newline | ||||
| 			content = content.replace(/  \n/g, "\n") | ||||
| @@ -592,6 +640,12 @@ async function eventToMessage(event, guild, di) { | ||||
|  | ||||
| 			content = await handleRoomOrMessageLinks(content, di) | ||||
|  | ||||
| 			const result = await checkWrittenMentions(content, guild, di) | ||||
| 			if (result) { | ||||
| 				content = result.content | ||||
| 				ensureJoined.push(result.ensureJoined) | ||||
| 			} | ||||
|  | ||||
| 			// Markdown needs to be escaped, though take care not to escape the middle of links | ||||
| 			// @ts-ignore bad type from turndown | ||||
| 			content = turndownService.escape(content) | ||||
| @@ -640,18 +694,6 @@ async function eventToMessage(event, guild, di) { | ||||
|  | ||||
| 	content = displayNameRunoff + replyLine + content | ||||
|  | ||||
| 	// Handling written @mentions: we need to look for candidate Discord members to join to the room | ||||
| 	let writtenMentionMatch = content.match(/(?:^|[^"[<>/A-Za-z0-9])@([A-Za-z][A-Za-z0-9._\[\]\(\)-]+):?/d) // /d flag for indices requires node.js 16+ | ||||
| 	if (writtenMentionMatch) { | ||||
| 		const results = await di.snow.guild.searchGuildMembers(guild.id, {query: writtenMentionMatch[1]}) | ||||
| 		if (results[0]) { | ||||
| 			assert(results[0].user) | ||||
| 			// @ts-ignore - typescript doesn't know about indices yet | ||||
| 			content = content.slice(0, writtenMentionMatch.indices[1][0]-1) + `<@${results[0].user.id}>` + content.slice(writtenMentionMatch.indices[1][1]) | ||||
| 			ensureJoined.push(results[0].user) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Split into 2000 character chunks | ||||
| 	const chunks = chunk(content, 2000) | ||||
| 	messages = messages.concat(chunks.map(content => ({ | ||||
|   | ||||
| @@ -1924,7 +1924,7 @@ test("event2message: mentioning PK discord users works", async t => { | ||||
| 			messagesToEdit: [], | ||||
| 			messagesToSend: [{ | ||||
| 				username: "cadence [they]", | ||||
| 				content: "I'm just <@196188877885538304> testing mentions", | ||||
| 				content: "I'm just **@Azalea &flwr; 🌺** (<@196188877885538304>) testing mentions", | ||||
| 				avatar_url: undefined | ||||
| 			}] | ||||
| 		} | ||||
| @@ -2845,7 +2845,7 @@ test("event2message: unknown emojis in the middle are linked", async t => { | ||||
| 	) | ||||
| }) | ||||
|  | ||||
| test("event2message: guessed @mentions may join members to mention", async t => { | ||||
| test("event2message: guessed @mentions in plaintext may join members to mention", async t => { | ||||
| 	let called = 0 | ||||
| 	const subtext = { | ||||
| 		user: { | ||||
| @@ -2893,6 +2893,56 @@ test("event2message: guessed @mentions may join members to mention", async t => | ||||
| 	t.equal(called, 1, "searchGuildMembers should be called once") | ||||
| }) | ||||
|  | ||||
| test("event2message: guessed @mentions in formatted body may join members to mention", async t => { | ||||
| 	let called = 0 | ||||
| 	const subtext = { | ||||
| 		user: { | ||||
| 			id: "321876634777218072", | ||||
| 			username: "subtextual", | ||||
| 			global_name: "subtext", | ||||
| 			discriminator: "0" | ||||
| 		} | ||||
| 	} | ||||
| 	t.deepEqual( | ||||
| 		await eventToMessage({ | ||||
| 			type: "m.room.message", | ||||
| 			sender: "@cadence:cadence.moe", | ||||
| 			content: { | ||||
| 				msgtype: "m.text", | ||||
| 				body: "wrong body", | ||||
| 				format: "org.matrix.custom.html", | ||||
| 				formatted_body: "<strong><em>HEY @SUBTEXT, WHAT FOOD WOULD YOU LIKE TO ORDER??</em></strong>" | ||||
| 			}, | ||||
| 			event_id: "$u5gSwSzv_ZQS3eM00mnTBCor8nx_A_AwuQz7e59PZk8", | ||||
| 			room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe" | ||||
| 		}, { | ||||
| 			id: "112760669178241024" | ||||
| 		}, { | ||||
| 			snow: { | ||||
| 				guild: { | ||||
| 					async searchGuildMembers(guildID, options) { | ||||
| 						called++ | ||||
| 						t.equal(guildID, "112760669178241024") | ||||
| 						t.deepEqual(options, {query: "SUBTEXT"}) | ||||
| 						return [subtext] | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		}), | ||||
| 		{ | ||||
| 			messagesToDelete: [], | ||||
| 			messagesToEdit: [], | ||||
| 			messagesToSend: [{ | ||||
| 				username: "cadence [they]", | ||||
| 				content: "**_HEY <@321876634777218072>, WHAT FOOD WOULD YOU LIKE TO ORDER??_**", | ||||
| 				avatar_url: undefined | ||||
| 			}], | ||||
| 			ensureJoined: [subtext.user] | ||||
| 		} | ||||
| 	) | ||||
| 	t.equal(called, 1, "searchGuildMembers should be called once") | ||||
| }) | ||||
|  | ||||
| test("event2message: guessed @mentions work with other matrix bridge old users", async t => { | ||||
| 	t.deepEqual( | ||||
| 		await eventToMessage({ | ||||
|   | ||||
							
								
								
									
										124
									
								
								test/data.js
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								test/data.js
									
									
									
									
									
								
							| @@ -1340,6 +1340,89 @@ module.exports = { | ||||
| 				components: [] | ||||
| 			} | ||||
| 		}, | ||||
| 		voice_message: { | ||||
| 			id: "1112476845783388160", | ||||
| 			type: 0, | ||||
| 			content: "", | ||||
| 			channel_id: "1099031887500034088", | ||||
| 			author: { | ||||
| 				id: "113340068197859328", | ||||
| 				username: "kumaccino", | ||||
| 				avatar: "b48302623a12bc7c59a71328f72ccb39", | ||||
| 				discriminator: "0", | ||||
| 				public_flags: 128, | ||||
| 				premium_type: 0, | ||||
| 				flags: 128, | ||||
| 				banner: null, | ||||
| 				accent_color: null, | ||||
| 				global_name: "kumaccino", | ||||
| 				avatar_decoration_data: null, | ||||
| 				banner_color: null | ||||
| 			}, | ||||
| 			attachments: [ | ||||
| 				{ | ||||
| 					id: "1112476845502365786", | ||||
| 					filename: "voice-message.ogg", | ||||
| 					size: 10584, | ||||
| 					url: "https://cdn.discordapp.com/attachments/1099031887500034088/1112476845502365786/voice-message.ogg?ex=65c92d4c&is=65b6b84c&hm=0654bab5027474cbe23875954fa117cf44d8914c144cd151879590fa1baf8b1c&", | ||||
| 					proxy_url: "https://media.discordapp.net/attachments/1099031887500034088/1112476845502365786/voice-message.ogg?ex=65c92d4c&is=65b6b84c&hm=0654bab5027474cbe23875954fa117cf44d8914c144cd151879590fa1baf8b1c&", | ||||
| 					duration_secs: 3.9600000381469727, | ||||
| 					waveform: "AAgXAAwAPBsCAAAAInEDFwAAAAAbMwATEBAAAAAAAAAAAAAAAA==", | ||||
| 					content_type: "audio/ogg" | ||||
| 				} | ||||
| 			], | ||||
| 			embeds: [], | ||||
| 			mentions: [], | ||||
| 			mention_roles: [], | ||||
| 			pinned: false, | ||||
| 			mention_everyone: false, | ||||
| 			tts: false, | ||||
| 			timestamp: "2023-05-28T20:25:48.855000+00:00", | ||||
| 			edited_timestamp: null, | ||||
| 			flags: 8192, | ||||
| 			components: [] | ||||
| 		}, | ||||
| 		misc_file: { | ||||
| 			id: "1174514575819931718", | ||||
| 			type: 0, | ||||
| 			content: "final final final revised draft", | ||||
| 			channel_id: "122155380120748034", | ||||
| 			author: { | ||||
| 				id: "142843483923677184", | ||||
| 				username: "huck", | ||||
| 				avatar: "a_1c7fda09a242d714570b4c828ef07504", | ||||
| 				discriminator: "0", | ||||
| 				public_flags: 512, | ||||
| 				premium_type: 2, | ||||
| 				flags: 512, | ||||
| 				banner: null, | ||||
| 				accent_color: null, | ||||
| 				global_name: null, | ||||
| 				avatar_decoration_data: null, | ||||
| 				banner_color: null | ||||
| 			}, | ||||
| 			attachments: [ | ||||
| 				{ | ||||
| 					id: "1174514575220158545", | ||||
| 					filename: "the.yml", | ||||
| 					size: 2274, | ||||
| 					url: "https://cdn.discordapp.com/attachments/122155380120748034/1174514575220158545/the.yml?ex=65cd6270&is=65baed70&hm=8c5f1b571784e3c7f99628492298815884e351ae0dc7c2ae40dd22d97caf27d9&", | ||||
| 					proxy_url: "https://media.discordapp.net/attachments/122155380120748034/1174514575220158545/the.yml?ex=65cd6270&is=65baed70&hm=8c5f1b571784e3c7f99628492298815884e351ae0dc7c2ae40dd22d97caf27d9&", | ||||
| 					content_type: "text/plain; charset=utf-8", | ||||
| 					content_scan_version: 0 | ||||
| 				} | ||||
| 			], | ||||
| 			embeds: [], | ||||
| 			mentions: [], | ||||
| 			mention_roles: [], | ||||
| 			pinned: false, | ||||
| 			mention_everyone: false, | ||||
| 			tts: false, | ||||
| 			timestamp: "2023-11-16T01:01:36.301000+00:00", | ||||
| 			edited_timestamp: null, | ||||
| 			flags: 0, | ||||
| 			components: [] | ||||
| 		}, | ||||
| 		simple_reply_to_reply_in_thread: { | ||||
| 			type: 19, | ||||
| 			tts: false, | ||||
| @@ -1681,6 +1764,47 @@ module.exports = { | ||||
| 			components: [] | ||||
| 		} | ||||
| 	}, | ||||
| 	pk_message: { | ||||
| 		pk_reply: { | ||||
| 			id: "1202543812644306965", | ||||
| 			type: 0, | ||||
| 			content: "this is a reply", | ||||
| 			channel_id: "1160894080998461480", | ||||
| 			author: { | ||||
| 				id: "1195662438662680720", | ||||
| 				username: "special name", | ||||
| 				avatar: "6b44a106659e78a2550474c61889194d", | ||||
| 				discriminator: "0000", | ||||
| 				public_flags: 0, | ||||
| 				flags: 0, | ||||
| 				bot: true, | ||||
| 				global_name: null | ||||
| 			}, | ||||
| 			attachments: [], | ||||
| 			embeds: [ | ||||
| 				{ | ||||
| 					type: "rich", | ||||
| 					description: "**[Reply to:](https://discord.com/channels/1160893336324931584/1160894080998461480/1202543413652881428)** now for my next experiment:", | ||||
| 					author: { | ||||
| 						name: "cadence [they] ↩️", | ||||
| 						icon_url: "https://cdn.discordapp.com/avatars/1162510387057545227/af0ead3b92cf6e448fdad80b4e7fc9e5.png", | ||||
| 						proxy_icon_url: "https://images-ext-1.discordapp.net/external/wWslraV-s-bLDwphL64YxeDm30M7PIhQQy0EQa8jpDc/https/cdn.discordapp.com/avatars/1162510387057545227/af0ead3b92cf6e448fdad80b4e7fc9e5.png" | ||||
| 					} | ||||
| 				} | ||||
| 			], | ||||
| 			mentions: [], | ||||
| 			mention_roles: [], | ||||
| 			pinned: false, | ||||
| 			mention_everyone: false, | ||||
| 			tts: false, | ||||
| 			timestamp: "2024-02-01T09:19:47.118000+00:00", | ||||
| 			edited_timestamp: null, | ||||
| 			flags: 0, | ||||
| 			components: [], | ||||
| 			application_id: "466378653216014359", | ||||
| 			webhook_id: "1195662438662680720" | ||||
| 		} | ||||
| 	}, | ||||
| 	message_with_embeds: { | ||||
| 		nothing_but_a_field: { | ||||
| 			guild_id: "497159726455455754", | ||||
|   | ||||
| @@ -12,7 +12,8 @@ INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom | ||||
| ('297272183716052993', '!rEOspnYqdOalaIFniV:cadence.moe', 'general', NULL, NULL, NULL), | ||||
| ('122155380120748034', '!cqeGDbPiMFAhLsqqqq:cadence.moe', 'cadences-mind', 'coding', NULL, NULL), | ||||
| ('176333891320283136', '!qzDBLKlildpzrrOnFZ:cadence.moe', '🌈丨davids-horse_she-took-the-kids', 'wonderland', NULL, 'mxc://cadence.moe/EVvrSkKIRONHjtRJsMLmHWLS'), | ||||
| ('489237891895768942', '!tnedrGVYKFNUdnegvf:tchncs.de', 'ex-room-doesnt-exist-any-more', NULL, NULL, NULL); | ||||
| ('489237891895768942', '!tnedrGVYKFNUdnegvf:tchncs.de', 'ex-room-doesnt-exist-any-more', NULL, NULL, NULL), | ||||
| ('1160894080998461480', '!TqlyQmifxGUggEmdBN:cadence.moe', 'ooyexperiment', NULL, NULL, NULL); | ||||
|  | ||||
| INSERT INTO sim (user_id, sim_name, localpart, mxid) VALUES | ||||
| ('0', 'bot', '_ooye_bot', '@_ooye_bot:cadence.moe'), | ||||
| @@ -24,8 +25,8 @@ INSERT INTO sim (user_id, sim_name, localpart, mxid) VALUES | ||||
| ('1109360903096369153', 'amanda', '_ooye_amanda', '@_ooye_amanda:cadence.moe'), | ||||
| ('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '_pk_zoego', '_ooye__pk_zoego', '@_ooye__pk_zoego:cadence.moe'); | ||||
|  | ||||
| INSERT INTO sim_proxy (user_id, proxy_owner_id) VALUES | ||||
| ('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '196188877885538304'); | ||||
| INSERT INTO sim_proxy (user_id, proxy_owner_id, displayname) VALUES | ||||
| ('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '196188877885538304', 'Azalea &flwr; 🌺'); | ||||
|  | ||||
| INSERT INTO sim_member (mxid, room_id, hashed_profile_content) VALUES | ||||
| ('@_ooye_bojack_horseman:cadence.moe', '!hYnGGlPHlbujVVfktC:cadence.moe', NULL); | ||||
| @@ -48,7 +49,8 @@ INSERT INTO message_channel (message_id, channel_id) VALUES | ||||
| ('1162005526675193909', '1162005314908999790'), | ||||
| ('1162625810109317170', '497161350934560778'), | ||||
| ('1158842413025071135', '176333891320283136'), | ||||
| ('1197612733600895076', '112760669178241024'); | ||||
| ('1197612733600895076', '112760669178241024'), | ||||
| ('1202543413652881428', '1160894080998461480'); | ||||
|  | ||||
| INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part, reaction_part, source) VALUES | ||||
| ('$X16nfVks1wsrhq4E9SSLiqrf2N8KD0erD0scZG7U5xg', 'm.room.message', 'm.text', '1126786462646550579', 0, 0, 1), | ||||
| @@ -74,7 +76,8 @@ INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part | ||||
| ('$0wEdIP8fhTq-P68xwo_gyUw-Zv0KA2aS2tfhdFSrLZc', 'm.room.message', 'm.text', '1162625810109317170', 1, 1, 1), | ||||
| ('$zJFjTvNn1w_YqpR4o4ISKUFisNRgZcu1KSMI_LADPVQ', 'm.room.message', 'm.notice', '1162625810109317170', 1, 0, 1), | ||||
| ('$dVCLyj6kxb3DaAWDtjcv2kdSny8JMMHdDhCMz8mDxVo', 'm.room.message', 'm.text', '1158842413025071135', 0, 0, 1), | ||||
| ('$7tJoMw1h44n2gxgLUE1T_YinGrLbK0x-TDY1z6M7GBw', 'm.room.message', 'm.text', '1197612733600895076', 0, 0, 1); | ||||
| ('$7tJoMw1h44n2gxgLUE1T_YinGrLbK0x-TDY1z6M7GBw', 'm.room.message', 'm.text', '1197612733600895076', 0, 0, 1), | ||||
| ('$NB6nPgO2tfXyIwwDSF0Ga0BUrsgX1S-0Xl-jAvI8ucU', 'm.room.message', 'm.text', '1202543413652881428', 0, 0, 0); | ||||
|  | ||||
| INSERT INTO file (discord_url, mxc_url) VALUES | ||||
| ('https://cdn.discordapp.com/attachments/497161332244742154/1124628646431297546/image.png', 'mxc://cadence.moe/qXoZktDqNtEGuOCZEADAMvhM'), | ||||
| @@ -92,7 +95,9 @@ INSERT INTO file (discord_url, mxc_url) VALUES | ||||
| ('https://cdn.discordapp.com/emojis/1125827250609201255.png', 'mxc://cadence.moe/pgdGTxAyEltccRgZKxdqzHHP'), | ||||
| ('https://cdn.discordapp.com/avatars/320067006521147393/5fc4ad85c1ea876709e9a7d3374a78a1.png?size=1024', 'mxc://cadence.moe/JPzSmALLirnIprlSMKohSSoX'), | ||||
| ('https://cdn.discordapp.com/emojis/288858540888686602.png', 'mxc://cadence.moe/mwZaCtRGAQQyOItagDeCocEO'), | ||||
| ('https://cdn.discordapp.com/attachments/112760669178241024/1197621094786531358/Ins_1960637570.mp4', 'mxc://cadence.moe/kMqLycqMURhVpwleWkmASpnU'); | ||||
| ('https://cdn.discordapp.com/attachments/112760669178241024/1197621094786531358/Ins_1960637570.mp4', 'mxc://cadence.moe/kMqLycqMURhVpwleWkmASpnU'), | ||||
| ('https://cdn.discordapp.com/attachments/1099031887500034088/1112476845502365786/voice-message.ogg', 'mxc://cadence.moe/MRRPDggXQMYkrUjTpxQbmcxB'), | ||||
| ('https://cdn.discordapp.com/attachments/122155380120748034/1174514575220158545/the.yml', 'mxc://cadence.moe/HnQIYQmmlIKwOQsbFsIGpzPP'); | ||||
|  | ||||
| INSERT INTO emoji (emoji_id, name, animated, mxc_url) VALUES | ||||
| ('230201364309868544', 'hippo', 0, 'mxc://cadence.moe/qWmbXeRspZRLPcjseyLmeyXC'), | ||||
|   | ||||
| @@ -48,6 +48,12 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not | ||||
| 		t.pass("it did not throw an error") | ||||
| 	}) | ||||
| 	await p | ||||
|  | ||||
| 	test("migrate: migration works the second time", async t => { | ||||
| 		await migrate.migrate(db) | ||||
| 		t.pass("it did not throw an error") | ||||
| 	}) | ||||
|  | ||||
| 	db.exec(fs.readFileSync(join(__dirname, "ooye-test-data.sql"), "utf8")) | ||||
| 	require("../db/orm.test") | ||||
| 	require("../discord/utils.test") | ||||
| @@ -63,6 +69,7 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not | ||||
| 	require("../d2m/converters/lottie.test") | ||||
| 	require("../d2m/converters/message-to-event.test") | ||||
| 	require("../d2m/converters/message-to-event.embeds.test") | ||||
| 	require("../d2m/converters/message-to-event.pk.test") | ||||
| 	require("../d2m/converters/pins-to-list.test") | ||||
| 	require("../d2m/converters/remove-reaction.test") | ||||
| 	require("../d2m/converters/thread-to-announcement.test") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Cadence Ember
					Cadence Ember