mirror of
https://gitdab.com/cadence/out-of-your-element.git
synced 2025-09-10 12:22:50 +02:00
Add foreign keys to database
This commit is contained in:
parent
931cacea6a
commit
8ad299b04c
14 changed files with 398 additions and 65 deletions
|
@ -430,6 +430,13 @@ async function unbridgeDeletedChannel(channel, guildID) {
|
|||
// leave room
|
||||
await api.leaveRoom(roomID)
|
||||
|
||||
// delete webhook on discord
|
||||
const webhook = select("webhook", ["webhook_id", "webhook_token"], {channel_id: channel.id}).get()
|
||||
if (webhook) {
|
||||
await discord.snow.webhook.deleteWebhook(webhook.webhook_id, webhook.webhook_token)
|
||||
db.prepare("DELETE FROM webhook WHERE channel_id = ?").run(channel.id)
|
||||
}
|
||||
|
||||
// delete room from database
|
||||
db.prepare("DELETE FROM channel_room WHERE room_id = ? AND channel_id = ?").run(roomID, channel.id)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ async function deleteMessage(data) {
|
|||
|
||||
const eventsToRedact = select("event_message", "event_id", {message_id: data.id}).pluck().all()
|
||||
db.prepare("DELETE FROM message_channel WHERE message_id = ?").run(data.id)
|
||||
db.prepare("DELETE FROM event_message WHERE message_id = ?").run(data.id)
|
||||
for (const eventID of eventsToRedact) {
|
||||
// Unfortunately, we can't specify a sender to do the redaction as, unless we find out that info via the audit logs
|
||||
await api.redactEvent(row.room_id, eventID)
|
||||
|
@ -35,7 +34,6 @@ async function deleteMessageBulk(data) {
|
|||
const sids = JSON.stringify(data.ids)
|
||||
const eventsToRedact = from("event_message").pluck("event_id").and("WHERE message_id IN (SELECT value FROM json_each(?))").all(sids)
|
||||
db.prepare("DELETE FROM message_channel WHERE message_id IN (SELECT value FROM json_each(?))").run(sids)
|
||||
db.prepare("DELETE FROM event_message WHERE message_id IN (SELECT value FROM json_each(?))").run(sids)
|
||||
for (const eventID of eventsToRedact) {
|
||||
// Awaiting will make it go slower, but since this could be a long-running operation either way, we want to leave rate limit capacity for other operations
|
||||
await api.redactEvent(roomID, eventID)
|
||||
|
|
|
@ -61,7 +61,7 @@ async function editMessage(message, guild, row) {
|
|||
|
||||
// 4. Send all the things.
|
||||
if (eventsToSend.length) {
|
||||
db.prepare("REPLACE INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(message.id, message.channel_id)
|
||||
db.prepare("INSERT OR IGNORE INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(message.id, message.channel_id)
|
||||
}
|
||||
for (const content of eventsToSend) {
|
||||
const eventType = content.$type
|
||||
|
|
|
@ -47,7 +47,7 @@ async function sendMessage(message, channel, guild, row) {
|
|||
const events = await messageToEvent.messageToEvent(message, guild, {}, {api})
|
||||
const eventIDs = []
|
||||
if (events.length) {
|
||||
db.prepare("REPLACE INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(message.id, message.channel_id)
|
||||
db.prepare("INSERT OR IGNORE INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(message.id, message.channel_id)
|
||||
if (senderMxid) api.sendTyping(roomID, false, senderMxid).catch(() => {})
|
||||
}
|
||||
for (const event of events) {
|
||||
|
|
|
@ -6,7 +6,8 @@ const {join} = require("path")
|
|||
async function migrate(db) {
|
||||
let files = fs.readdirSync(join(__dirname, "migrations"))
|
||||
files = files.sort()
|
||||
db.prepare("CREATE TABLE IF NOT EXISTS migration (filename TEXT NOT NULL)").run()
|
||||
db.prepare("CREATE TABLE IF NOT EXISTS migration (filename TEXT NOT NULL, PRIMARY KEY (filename)) WITHOUT ROWID").run()
|
||||
/** @type {string} */
|
||||
let progress = db.prepare("SELECT * FROM migration").pluck().get()
|
||||
if (!progress) {
|
||||
progress = ""
|
||||
|
@ -37,6 +38,8 @@ async function migrate(db) {
|
|||
if (migrationRan) {
|
||||
console.log("Database migrations all done.")
|
||||
}
|
||||
|
||||
db.pragma("foreign_keys = on")
|
||||
}
|
||||
|
||||
module.exports.migrate = migrate
|
||||
|
|
164
src/db/migrations/0016-foreign-keys.sql
Normal file
164
src/db/migrations/0016-foreign-keys.sql
Normal file
|
@ -0,0 +1,164 @@
|
|||
-- /docs/foreign-keys.md
|
||||
|
||||
-- 2
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
-- *** channel_room ***
|
||||
|
||||
-- 4
|
||||
-- adding UNIQUE to room_id here will auto-generate the usable index we wanted
|
||||
CREATE TABLE "new_channel_room" (
|
||||
"channel_id" TEXT NOT NULL,
|
||||
"room_id" TEXT NOT NULL UNIQUE,
|
||||
"name" TEXT NOT NULL,
|
||||
"nick" TEXT,
|
||||
"thread_parent" TEXT,
|
||||
"custom_avatar" TEXT,
|
||||
"last_bridged_pin_timestamp" INTEGER,
|
||||
"speedbump_id" TEXT,
|
||||
"speedbump_checked" INTEGER,
|
||||
"speedbump_webhook_id" TEXT,
|
||||
"guild_id" TEXT,
|
||||
PRIMARY KEY("channel_id"),
|
||||
FOREIGN KEY("guild_id") REFERENCES "guild_active"("guild_id") ON DELETE CASCADE
|
||||
) WITHOUT ROWID;
|
||||
-- 5
|
||||
INSERT INTO new_channel_room (channel_id, room_id, name, nick, thread_parent, custom_avatar, last_bridged_pin_timestamp, speedbump_id, speedbump_checked, speedbump_webhook_id, guild_id) SELECT channel_id, room_id, name, nick, thread_parent, custom_avatar, last_bridged_pin_timestamp, speedbump_id, speedbump_checked, speedbump_webhook_id, guild_id FROM channel_room;
|
||||
-- 6
|
||||
DROP TABLE channel_room;
|
||||
-- 7
|
||||
ALTER TABLE new_channel_room RENAME TO channel_room;
|
||||
|
||||
-- *** message_channel ***
|
||||
|
||||
-- 4
|
||||
CREATE TABLE "new_message_channel" (
|
||||
"message_id" TEXT NOT NULL,
|
||||
"channel_id" TEXT NOT NULL,
|
||||
PRIMARY KEY("message_id"),
|
||||
FOREIGN KEY("channel_id") REFERENCES "channel_room"("channel_id") ON DELETE CASCADE
|
||||
) WITHOUT ROWID;
|
||||
-- 5
|
||||
-- don't copy any orphaned messages
|
||||
INSERT INTO new_message_channel (message_id, channel_id) SELECT message_id, channel_id FROM message_channel WHERE channel_id IN (SELECT channel_id FROM channel_room);
|
||||
-- 6
|
||||
DROP TABLE message_channel;
|
||||
-- 7
|
||||
ALTER TABLE new_message_channel RENAME TO message_channel;
|
||||
|
||||
-- *** event_message ***
|
||||
|
||||
-- clean up any orphaned events
|
||||
DELETE FROM event_message WHERE message_id NOT IN (SELECT message_id FROM message_channel);
|
||||
-- 4
|
||||
CREATE TABLE "new_event_message" (
|
||||
"event_id" TEXT NOT NULL,
|
||||
"event_type" TEXT,
|
||||
"event_subtype" TEXT,
|
||||
"message_id" TEXT NOT NULL,
|
||||
"part" INTEGER NOT NULL,
|
||||
"reaction_part" INTEGER NOT NULL,
|
||||
"source" INTEGER NOT NULL,
|
||||
PRIMARY KEY("message_id","event_id"),
|
||||
FOREIGN KEY("message_id") REFERENCES "message_channel"("message_id") ON DELETE CASCADE
|
||||
) WITHOUT ROWID;
|
||||
-- 5
|
||||
INSERT INTO new_event_message (event_id, event_type, event_subtype, message_id, part, reaction_part, source) SELECT event_id, event_type, event_subtype, message_id, part, reaction_part, source FROM event_message;
|
||||
-- 6
|
||||
DROP TABLE event_message;
|
||||
-- 7
|
||||
ALTER TABLE new_event_message RENAME TO event_message;
|
||||
|
||||
-- *** guild_space ***
|
||||
|
||||
-- 4
|
||||
CREATE TABLE "new_guild_space" (
|
||||
"guild_id" TEXT NOT NULL,
|
||||
"space_id" TEXT NOT NULL,
|
||||
"privacy_level" INTEGER NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY("guild_id"),
|
||||
FOREIGN KEY("guild_id") REFERENCES "guild_active"("guild_id") ON DELETE CASCADE
|
||||
) WITHOUT ROWID;
|
||||
-- 5
|
||||
INSERT INTO new_guild_space (guild_id, space_id, privacy_level) SELECT guild_id, space_id, privacy_level FROM guild_space;
|
||||
-- 6
|
||||
DROP TABLE guild_space;
|
||||
-- 7
|
||||
ALTER TABLE new_guild_space RENAME TO guild_space;
|
||||
|
||||
-- *** member_cache ***
|
||||
|
||||
-- 4
|
||||
CREATE TABLE "new_member_cache" (
|
||||
"room_id" TEXT NOT NULL,
|
||||
"mxid" TEXT NOT NULL,
|
||||
"displayname" TEXT,
|
||||
"avatar_url" TEXT, power_level INTEGER NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY("room_id","mxid"),
|
||||
FOREIGN KEY("room_id") REFERENCES "channel_room"("room_id") ON DELETE CASCADE
|
||||
) WITHOUT ROWID;
|
||||
-- 5
|
||||
INSERT INTO new_member_cache (room_id, mxid, displayname, avatar_url) SELECT room_id, mxid, displayname, avatar_url FROM member_cache WHERE room_id IN (SELECT room_id FROM channel_room);
|
||||
-- 6
|
||||
DROP TABLE member_cache;
|
||||
-- 7
|
||||
ALTER TABLE new_member_cache RENAME TO member_cache;
|
||||
|
||||
-- *** reaction ***
|
||||
|
||||
-- 4
|
||||
CREATE TABLE "new_reaction" (
|
||||
"hashed_event_id" INTEGER NOT NULL,
|
||||
"message_id" TEXT NOT NULL,
|
||||
"encoded_emoji" TEXT NOT NULL,
|
||||
PRIMARY KEY("hashed_event_id"),
|
||||
FOREIGN KEY("message_id") REFERENCES "message_channel"("message_id") ON DELETE CASCADE
|
||||
) WITHOUT ROWID;
|
||||
-- 5
|
||||
INSERT INTO new_reaction (hashed_event_id, message_id, encoded_emoji) SELECT hashed_event_id, message_id, encoded_emoji FROM reaction WHERE message_id IN (SELECT message_id FROM message_channel);
|
||||
-- 6
|
||||
DROP TABLE reaction;
|
||||
-- 7
|
||||
ALTER TABLE new_reaction RENAME TO reaction;
|
||||
|
||||
-- *** webhook ***
|
||||
|
||||
-- 4
|
||||
-- using RESTRICT instead of CASCADE as a reminder that the webhooks also need to be deleted using the Discord API, it can't just be entirely automatic
|
||||
CREATE TABLE "new_webhook" (
|
||||
"channel_id" TEXT NOT NULL,
|
||||
"webhook_id" TEXT NOT NULL,
|
||||
"webhook_token" TEXT NOT NULL,
|
||||
PRIMARY KEY("channel_id"),
|
||||
FOREIGN KEY("channel_id") REFERENCES "channel_room"("channel_id") ON DELETE RESTRICT
|
||||
) WITHOUT ROWID;
|
||||
-- 5
|
||||
INSERT INTO new_webhook (channel_id, webhook_id, webhook_token) SELECT channel_id, webhook_id, webhook_token FROM webhook WHERE channel_id IN (SELECT channel_id FROM channel_room);
|
||||
-- 6
|
||||
DROP TABLE webhook;
|
||||
-- 7
|
||||
ALTER TABLE new_webhook RENAME TO webhook;
|
||||
|
||||
-- *** sim ***
|
||||
|
||||
-- 4
|
||||
-- while we're at it, rebuild this table to give it WITHOUT ROWID, remove UNIQUE, and drop the localpart column. no foreign keys needed
|
||||
CREATE TABLE "new_sim" (
|
||||
"user_id" TEXT NOT NULL,
|
||||
"sim_name" TEXT NOT NULL,
|
||||
"mxid" TEXT NOT NULL,
|
||||
PRIMARY KEY("user_id")
|
||||
) WITHOUT ROWID;
|
||||
-- 5
|
||||
INSERT INTO new_sim (user_id, sim_name, mxid) SELECT user_id, sim_name, mxid FROM sim;
|
||||
-- 6
|
||||
DROP TABLE sim;
|
||||
-- 7
|
||||
ALTER TABLE new_sim RENAME TO sim;
|
||||
|
||||
-- *** end ***
|
||||
|
||||
-- 10
|
||||
PRAGMA foreign_key_check;
|
||||
-- 11
|
||||
COMMIT;
|
|
@ -13,7 +13,6 @@ const utils = sync.require("../converters/utils")
|
|||
*/
|
||||
async function deleteMessage(event) {
|
||||
const rows = from("event_message").join("message_channel", "message_id").select("channel_id", "message_id").where({event_id: event.redacts}).all()
|
||||
db.prepare("DELETE FROM event_message WHERE event_id = ?").run(event.redacts)
|
||||
for (const row of rows) {
|
||||
db.prepare("DELETE FROM message_channel WHERE message_id = ?").run(row.message_id)
|
||||
await discord.snow.channel.deleteMessage(row.channel_id, row.message_id, event.content.reason)
|
||||
|
|
|
@ -102,14 +102,13 @@ async function sendEvent(event) {
|
|||
|
||||
for (const id of messagesToDelete) {
|
||||
db.prepare("DELETE FROM message_channel WHERE message_id = ?").run(id)
|
||||
db.prepare("DELETE FROM event_message WHERE message_id = ?").run(id)
|
||||
await channelWebhook.deleteMessageWithWebhook(channelID, id, threadID)
|
||||
}
|
||||
|
||||
for (const message of messagesToSend) {
|
||||
const reactionPart = messagesToEdit.length === 0 && message === messagesToSend[messagesToSend.length - 1] ? 0 : 1
|
||||
const messageResponse = await channelWebhook.sendMessageWithWebhook(channelID, message, threadID)
|
||||
db.prepare("REPLACE INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(messageResponse.id, threadID || channelID)
|
||||
db.prepare("INSERT INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(messageResponse.id, threadID || channelID)
|
||||
db.prepare("INSERT INTO event_message (event_id, event_type, event_subtype, message_id, part, reaction_part, source) VALUES (?, ?, ?, ?, ?, ?, 0)").run(event.event_id, event.type, event.content["msgtype"] || null, messageResponse.id, eventPart, reactionPart) // source 0 = matrix
|
||||
|
||||
eventPart = 1
|
||||
|
|
|
@ -258,7 +258,13 @@ async function getMemberFromCacheOrHomeserver(roomID, mxid, api) {
|
|||
const row = select("member_cache", ["displayname", "avatar_url"], {room_id: roomID, mxid}).get()
|
||||
if (row) return row
|
||||
return api.getStateEvent(roomID, "m.room.member", mxid).then(event => {
|
||||
db.prepare("REPLACE INTO member_cache (room_id, mxid, displayname, avatar_url) VALUES (?, ?, ?, ?)").run(roomID, mxid, event?.displayname || null, event?.avatar_url || null)
|
||||
const displayname = event?.displayname || null
|
||||
const avatar_url = event?.avatar_url || null
|
||||
db.prepare("INSERT INTO member_cache (room_id, mxid, displayname, avatar_url) VALUES (?, ?, ?, ?) ON CONFLICT DO UPDATE SET displayname = ?, avatar_url = ?").run(
|
||||
roomID, mxid,
|
||||
displayname, avatar_url,
|
||||
displayname, avatar_url
|
||||
)
|
||||
return event
|
||||
}).catch(() => {
|
||||
return {displayname: null, avatar_url: null}
|
||||
|
|
|
@ -559,7 +559,7 @@ test("event2message: lists are bridged correctly", async t => {
|
|||
"transaction_id": "m1692967313951.441"
|
||||
},
|
||||
"event_id": "$l-xQPY5vNJo3SNxU9d8aOWNVD1glMslMyrp4M_JEF70",
|
||||
"room_id": "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
||||
"room_id": "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||
}),
|
||||
{
|
||||
ensureJoined: [],
|
||||
|
@ -662,7 +662,7 @@ test("event2message: code block contents are formatted correctly and not escaped
|
|||
formatted_body: "<pre><code>input = input.replace(/(<\\/?([^ >]+)[^>]*>)?\\n(<\\/?([^ >]+)[^>]*>)?/g,\n_input_ = input = input.replace(/(<\\/?([^ >]+)[^>]*>)?\\n(<\\/?([^ >]+)[^>]*>)?/g,\n</code></pre>\n<p><code>input = input.replace(/(<\\/?([^ >]+)[^>]*>)?\\n(<\\/?([^ >]+)[^>]*>)?/g,</code></p>\n"
|
||||
},
|
||||
event_id: "$pGkWQuGVmrPNByrFELxhzI6MCBgJecr5I2J3z88Gc2s",
|
||||
room_id: "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||
}),
|
||||
{
|
||||
ensureJoined: [],
|
||||
|
@ -692,7 +692,7 @@ test("event2message: code blocks use double backtick as delimiter when necessary
|
|||
formatted_body: "<code>backtick in ` the middle</code>, <code>backtick at the edge`</code>"
|
||||
},
|
||||
event_id: "$pGkWQuGVmrPNByrFELxhzI6MCBgJecr5I2J3z88Gc2s",
|
||||
room_id: "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||
}),
|
||||
{
|
||||
ensureJoined: [],
|
||||
|
@ -722,7 +722,7 @@ test("event2message: inline code is converted to code block if it contains both
|
|||
formatted_body: "<code>` one two ``</code>"
|
||||
},
|
||||
event_id: "$pGkWQuGVmrPNByrFELxhzI6MCBgJecr5I2J3z88Gc2s",
|
||||
room_id: "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||
}),
|
||||
{
|
||||
ensureJoined: [],
|
||||
|
@ -752,7 +752,7 @@ test("event2message: code blocks are uploaded as attachments instead if they con
|
|||
formatted_body: 'So if you run code like this<pre><code class="language-java">System.out.println("```");</code></pre>it should print a markdown formatted code block'
|
||||
},
|
||||
event_id: "$pGkWQuGVmrPNByrFELxhzI6MCBgJecr5I2J3z88Gc2s",
|
||||
room_id: "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||
}),
|
||||
{
|
||||
ensureJoined: [],
|
||||
|
@ -784,7 +784,7 @@ test("event2message: code blocks are uploaded as attachments instead if they con
|
|||
formatted_body: 'So if you run code like this<pre><code>System.out.println("```");</code></pre>it should print a markdown formatted code block'
|
||||
},
|
||||
event_id: "$pGkWQuGVmrPNByrFELxhzI6MCBgJecr5I2J3z88Gc2s",
|
||||
room_id: "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||
}),
|
||||
{
|
||||
ensureJoined: [],
|
||||
|
@ -821,7 +821,7 @@ test("event2message: characters are encoded properly in code blocks", async t =>
|
|||
+ '\n</code></pre>'
|
||||
},
|
||||
event_id: "$pGkWQuGVmrPNByrFELxhzI6MCBgJecr5I2J3z88Gc2s",
|
||||
room_id: "!BpMdOUkWWhFxmTrENV:cadence.moe"
|
||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||
}),
|
||||
{
|
||||
ensureJoined: [],
|
||||
|
@ -902,7 +902,7 @@ test("event2message: lists have appropriate line breaks", async t => {
|
|||
'm.mentions': {},
|
||||
msgtype: 'm.text'
|
||||
},
|
||||
room_id: '!cBxtVRxDlZvSVhJXVK:cadence.moe',
|
||||
room_id: '!TqlyQmifxGUggEmdBN:cadence.moe',
|
||||
sender: '@Milan:tchncs.de',
|
||||
type: 'm.room.message',
|
||||
}),
|
||||
|
@ -943,7 +943,7 @@ test("event2message: ordered list start attribute works", async t => {
|
|||
'm.mentions': {},
|
||||
msgtype: 'm.text'
|
||||
},
|
||||
room_id: '!cBxtVRxDlZvSVhJXVK:cadence.moe',
|
||||
room_id: '!TqlyQmifxGUggEmdBN:cadence.moe',
|
||||
sender: '@Milan:tchncs.de',
|
||||
type: 'm.room.message',
|
||||
}),
|
||||
|
@ -1088,7 +1088,7 @@ test("event2message: rich reply to a rich reply to a multi-line message should c
|
|||
content: {
|
||||
body: "> <@cadence:cadence.moe> I just checked in a fix that will probably work, can you try reproducing this on the latest `main` branch and see if I fixed it?\n\nwill try later (tomorrow if I don't forgor)",
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: "<mx-reply><blockquote><a href=\"https://matrix.to/#/!cBxtVRxDlZvSVhJXVK:cadence.moe/$A0Rj559NKOh2VndCZSTJXcvgi42gZWVfVQt73wA2Hn0?via=matrix.org&via=cadence.moe&via=syndicated.gay\">In reply to</a> <a href=\"https://matrix.to/#/@cadence:cadence.moe\">@cadence:cadence.moe</a><br />I just checked in a fix that will probably work, can you try reproducing this on the latest <code>main</code> branch and see if I fixed it?</blockquote></mx-reply>will try later (tomorrow if I don't forgor)",
|
||||
formatted_body: "<mx-reply><blockquote><a href=\"https://matrix.to/#/!TqlyQmifxGUggEmdBN:cadence.moe/$A0Rj559NKOh2VndCZSTJXcvgi42gZWVfVQt73wA2Hn0?via=matrix.org&via=cadence.moe&via=syndicated.gay\">In reply to</a> <a href=\"https://matrix.to/#/@cadence:cadence.moe\">@cadence:cadence.moe</a><br />I just checked in a fix that will probably work, can you try reproducing this on the latest <code>main</code> branch and see if I fixed it?</blockquote></mx-reply>will try later (tomorrow if I don't forgor)",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
event_id: "$A0Rj559NKOh2VndCZSTJXcvgi42gZWVfVQt73wA2Hn0"
|
||||
|
@ -1111,7 +1111,7 @@ test("event2message: rich reply to a rich reply to a multi-line message should c
|
|||
"msgtype": "m.text",
|
||||
"body": "> <@solonovamax:matrix.org> multipart messages will be deleted if the message is edited to require less space\n> \n> \n> steps to reproduce:\n> \n> 1. send a message that is longer than 2000 characters (discord character limit)\n> - bot will split message into two messages on discord\n> 2. edit message to be under 2000 characters (discord character limit)\n> - bot will delete one of the messages on discord, and then edit the other one to include the edited content\n> - the bot will *then* delete the message on matrix (presumably) because one of the messages on discord was deleted (by \n\nI just checked in a fix that will probably work, can you try reproducing this on the latest `main` branch and see if I fixed it?",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!cBxtVRxDlZvSVhJXVK:cadence.moe/$u4OD19vd2GETkOyhgFVla92oDKI4ojwBf2-JeVCG7EI?via=cadence.moe&via=matrix.org&via=conduit.rory.gay\">In reply to</a> <a href=\"https://matrix.to/#/@solonovamax:matrix.org\">@solonovamax:matrix.org</a><br /><p>multipart messages will be deleted if the message is edited to require less space</p>\n<p>steps to reproduce:</p>\n<ol>\n<li>send a message that is longer than 2000 characters (discord character limit)</li>\n</ol>\n<ul>\n<li>bot will split message into two messages on discord</li>\n</ul>\n<ol start=\"2\">\n<li>edit message to be under 2000 characters (discord character limit)</li>\n</ol>\n<ul>\n<li>bot will delete one of the messages on discord, and then edit the other one to include the edited content</li>\n<li>the bot will <em>then</em> delete the message on matrix (presumably) because one of the messages on discord was deleted (by</li>\n</ul>\n</blockquote></mx-reply>I just checked in a fix that will probably work, can you try reproducing this on the latest <code>main</code> branch and see if I fixed it?",
|
||||
"formatted_body": "<mx-reply><blockquote><a href=\"https://matrix.to/#/!TqlyQmifxGUggEmdBN:cadence.moe/$u4OD19vd2GETkOyhgFVla92oDKI4ojwBf2-JeVCG7EI?via=cadence.moe&via=matrix.org&via=conduit.rory.gay\">In reply to</a> <a href=\"https://matrix.to/#/@solonovamax:matrix.org\">@solonovamax:matrix.org</a><br /><p>multipart messages will be deleted if the message is edited to require less space</p>\n<p>steps to reproduce:</p>\n<ol>\n<li>send a message that is longer than 2000 characters (discord character limit)</li>\n</ol>\n<ul>\n<li>bot will split message into two messages on discord</li>\n</ul>\n<ol start=\"2\">\n<li>edit message to be under 2000 characters (discord character limit)</li>\n</ol>\n<ul>\n<li>bot will delete one of the messages on discord, and then edit the other one to include the edited content</li>\n<li>the bot will <em>then</em> delete the message on matrix (presumably) because one of the messages on discord was deleted (by</li>\n</ul>\n</blockquote></mx-reply>I just checked in a fix that will probably work, can you try reproducing this on the latest <code>main</code> branch and see if I fixed it?",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": "$u4OD19vd2GETkOyhgFVla92oDKI4ojwBf2-JeVCG7EI"
|
||||
|
@ -1123,7 +1123,7 @@ test("event2message: rich reply to a rich reply to a multi-line message should c
|
|||
"age": 19069564
|
||||
},
|
||||
"event_id": "$A0Rj559NKOh2VndCZSTJXcvgi42gZWVfVQt73wA2Hn0",
|
||||
"room_id": "!cBxtVRxDlZvSVhJXVK:cadence.moe"
|
||||
"room_id": "!TqlyQmifxGUggEmdBN:cadence.moe"
|
||||
})
|
||||
},
|
||||
snow: {
|
||||
|
@ -3476,6 +3476,56 @@ test("event2message: colon after mentions is stripped", async t => {
|
|||
})
|
||||
|
||||
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: "!qzDBLKlildpzrrOnFZ: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, "!qzDBLKlildpzrrOnFZ:cadence.moe")
|
||||
t.equal(type, "m.room.member")
|
||||
t.equal(stateKey, "@should_be_newly_cached:cadence.moe")
|
||||
return {
|
||||
avatar_url: "mxc://cadence.moe/this_is_the_avatar"
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
{
|
||||
ensureJoined: [],
|
||||
messagesToDelete: [],
|
||||
messagesToEdit: [],
|
||||
messagesToSend: [{
|
||||
username: "should_be_newly_cached",
|
||||
content: "testing the member state cache",
|
||||
avatar_url: "https://bridge.example.org/download/matrix/cadence.moe/this_is_the_avatar",
|
||||
allowed_mentions: {
|
||||
parse: ["users", "roles"]
|
||||
}
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!qzDBLKlildpzrrOnFZ:cadence.moe"}).all(), [
|
||||
{avatar_url: "mxc://cadence.moe/this_is_the_avatar", displayname: null, mxid: "@should_be_newly_cached:cadence.moe"}
|
||||
])
|
||||
t.equal(called, 1, "getStateEvent should be called once")
|
||||
})
|
||||
|
||||
test("event2message: does not cache the member if the room is not known", async t => {
|
||||
let called = 0
|
||||
t.deepEqual(
|
||||
await eventToMessage({
|
||||
|
@ -3511,7 +3561,7 @@ test("event2message: caches the member if the member is not known", async t => {
|
|||
messagesToSend: [{
|
||||
username: "should_be_newly_cached",
|
||||
content: "testing the member state cache",
|
||||
avatar_url: "https://bridge.example.org/download/matrix/cadence.moe/this_is_the_avatar",
|
||||
avatar_url: undefined,
|
||||
allowed_mentions: {
|
||||
parse: ["users", "roles"]
|
||||
}
|
||||
|
@ -3519,9 +3569,7 @@ test("event2message: caches the member if the member is not known", async t => {
|
|||
}
|
||||
)
|
||||
|
||||
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!should_be_newly_cached:cadence.moe"}).all(), [
|
||||
{avatar_url: "mxc://cadence.moe/this_is_the_avatar", displayname: null, mxid: "@should_be_newly_cached:cadence.moe"}
|
||||
])
|
||||
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!should_be_newly_cached:cadence.moe"}).all(), [])
|
||||
t.equal(called, 1, "getStateEvent should be called once")
|
||||
})
|
||||
|
||||
|
@ -3580,7 +3628,7 @@ test("event2message: overly long usernames are shifted into the message content"
|
|||
},
|
||||
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
|
||||
origin_server_ts: 1688301929913,
|
||||
room_id: "!should_be_newly_cached_2:cadence.moe",
|
||||
room_id: "!cqeGDbPiMFAhLsqqqq:cadence.moe",
|
||||
sender: "@should_be_newly_cached_2:cadence.moe",
|
||||
type: "m.room.message",
|
||||
unsigned: {
|
||||
|
@ -3590,7 +3638,7 @@ test("event2message: overly long usernames are shifted into the message content"
|
|||
api: {
|
||||
getStateEvent: async (roomID, type, stateKey) => {
|
||||
called++
|
||||
t.equal(roomID, "!should_be_newly_cached_2:cadence.moe")
|
||||
t.equal(roomID, "!cqeGDbPiMFAhLsqqqq:cadence.moe")
|
||||
t.equal(type, "m.room.member")
|
||||
t.equal(stateKey, "@should_be_newly_cached_2:cadence.moe")
|
||||
return {
|
||||
|
@ -3613,7 +3661,7 @@ test("event2message: overly long usernames are shifted into the message content"
|
|||
}]
|
||||
}
|
||||
)
|
||||
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!should_be_newly_cached_2:cadence.moe"}).all(), [
|
||||
t.deepEqual(select("member_cache", ["avatar_url", "displayname", "mxid"], {room_id: "!cqeGDbPiMFAhLsqqqq:cadence.moe"}).all(), [
|
||||
{avatar_url: null, displayname: "I am BLACK I am WHITE I am SHORT I am LONG I am EVERYTHING YOU THINK IS IMPORTANT and I DON'T MATTER", mxid: "@should_be_newly_cached_2:cadence.moe"}
|
||||
])
|
||||
t.equal(called, 1, "getStateEvent should be called once")
|
||||
|
@ -3628,7 +3676,7 @@ test("event2message: overly long usernames are not treated specially when the ms
|
|||
},
|
||||
event_id: "$g07oYSZFWBkxohNEfywldwgcWj1hbhDzQ1sBAKvqOOU",
|
||||
origin_server_ts: 1688301929913,
|
||||
room_id: "!should_be_newly_cached_2:cadence.moe",
|
||||
room_id: "!cqeGDbPiMFAhLsqqqq:cadence.moe",
|
||||
sender: "@should_be_newly_cached_2:cadence.moe",
|
||||
type: "m.room.message",
|
||||
unsigned: {
|
||||
|
@ -4477,7 +4525,7 @@ slow()("event2message: all unknown chess emojis are reuploaded as a sprite sheet
|
|||
formatted_body: "testing <img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/lHfmJpzgoNyNtYHdAmBHxXix\" title=\":chess_good_move:\" alt=\":chess_good_move:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/MtRdXixoKjKKOyHJGWLsWLNU\" title=\":chess_incorrect:\" alt=\":chess_incorrect:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/HXfFuougamkURPPMflTJRxGc\" title=\":chess_blund:\" alt=\":chess_blund:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/ikYKbkhGhMERAuPPbsnQzZiX\" title=\":chess_brilliant_move:\" alt=\":chess_brilliant_move:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/AYPpqXzVJvZdzMQJGjioIQBZ\" title=\":chess_blundest:\" alt=\":chess_blundest:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/UVuzvpVUhqjiueMxYXJiFEAj\" title=\":chess_draw_black:\" alt=\":chess_draw_black:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/lHfmJpzgoNyNtYHdAmBHxXix\" title=\":chess_good_move:\" alt=\":chess_good_move:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/MtRdXixoKjKKOyHJGWLsWLNU\" title=\":chess_incorrect:\" alt=\":chess_incorrect:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/HXfFuougamkURPPMflTJRxGc\" title=\":chess_blund:\" alt=\":chess_blund:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/ikYKbkhGhMERAuPPbsnQzZiX\" title=\":chess_brilliant_move:\" alt=\":chess_brilliant_move:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/AYPpqXzVJvZdzMQJGjioIQBZ\" title=\":chess_blundest:\" alt=\":chess_blundest:\"><img data-mx-emoticon height=\"32\" src=\"mxc://cadence.moe/UVuzvpVUhqjiueMxYXJiFEAj\" title=\":chess_draw_black:\" alt=\":chess_draw_black:\">"
|
||||
},
|
||||
event_id: "$Me6iE8C8CZyrDEOYYrXKSYRuuh_25Jj9kZaNrf7LKr4",
|
||||
room_id: "!maggESguZBqGBZtSnr:cadence.moe"
|
||||
room_id: "!kLRqKKUQXcibIMtOpl:cadence.moe"
|
||||
}, {}, {mxcDownloader: mockGetAndConvertEmoji})
|
||||
const testResult = {
|
||||
content: messages.messagesToSend[0].content,
|
||||
|
|
|
@ -199,18 +199,29 @@ sync.addTemporaryListener(as, "type:m.room.member", guard("m.room.member",
|
|||
async event => {
|
||||
if (event.state_key[0] !== "@") return
|
||||
if (utils.eventSenderIsFromDiscord(event.state_key)) return
|
||||
|
||||
if (event.content.membership === "leave" || event.content.membership === "ban") {
|
||||
// Member is gone
|
||||
db.prepare("DELETE FROM member_cache WHERE room_id = ? and mxid = ?").run(event.room_id, event.state_key)
|
||||
} else {
|
||||
// Member is here
|
||||
db.prepare("INSERT INTO member_cache (room_id, mxid, displayname, avatar_url) VALUES (?, ?, ?, ?) ON CONFLICT DO UPDATE SET displayname = ?, avatar_url = ?")
|
||||
.run(
|
||||
event.room_id, event.state_key,
|
||||
event.content.displayname || null, event.content.avatar_url || null,
|
||||
event.content.displayname || null, event.content.avatar_url || null
|
||||
)
|
||||
return db.prepare("DELETE FROM member_cache WHERE room_id = ? and mxid = ?").run(event.room_id, event.state_key)
|
||||
}
|
||||
|
||||
const room = select("channel_room", "room_id", {room_id: event.room_id})
|
||||
if (!room) return // don't cache members in unbridged rooms
|
||||
|
||||
// Member is here
|
||||
let powerLevel = 0
|
||||
try {
|
||||
/** @type {Ty.Event.M_Power_Levels} */
|
||||
const powerLevelsEvent = await api.getStateEvent(event.room_id, "m.room.power_levels", "")
|
||||
powerLevel = powerLevelsEvent.users?.[event.state_key] ?? powerLevelsEvent.users_default ?? 0
|
||||
} catch (e) {}
|
||||
const displayname = event.content.displayname || null
|
||||
const avatar_url = event.content.avatar_url
|
||||
db.prepare("INSERT INTO member_cache (room_id, mxid, displayname, avatar_url, power_level) VALUES (?, ?, ?, ?, ?) ON CONFLICT DO UPDATE SET displayname = ?, avatar_url = ?, power_level = ?").run(
|
||||
event.room_id, event.state_key,
|
||||
displayname, avatar_url, powerLevel,
|
||||
displayname, avatar_url, powerLevel
|
||||
)
|
||||
}))
|
||||
|
||||
sync.addTemporaryListener(as, "type:m.room.power_levels", guard("m.room.power_levels",
|
||||
|
|
|
@ -87,7 +87,8 @@ as.router.get("/oauth", defineEventHandler(async event => {
|
|||
// Set auto-create for the guild
|
||||
// @ts-ignore
|
||||
if (managedGuilds.includes(parsedQuery.data.guild_id)) {
|
||||
db.prepare("REPLACE INTO guild_active (guild_id, autocreate) VALUES (?, ?)").run(parsedQuery.data.guild_id, +!session.data.selfService)
|
||||
const autocreateInteger = +!session.data.selfService
|
||||
db.prepare("INSERT INTO guild_active (guild_id, autocreate) VALUES (?, ?) ON CONFLICT DO UPDATE SET autocreate = ?").run(parsedQuery.data.guild_id, autocreateInteger, autocreateInteger)
|
||||
}
|
||||
|
||||
if (parsedQuery.data.guild_id) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue