Add foreign keys to database
This commit is contained in:
parent
931cacea6a
commit
8ad299b04c
14 changed files with 398 additions and 65 deletions
98
docs/foreign-keys.md
Normal file
98
docs/foreign-keys.md
Normal file
|
@ -0,0 +1,98 @@
|
|||
# Foreign keys in the Out Of Your Element database
|
||||
|
||||
Historically, Out Of Your Element did not use foreign keys in the database, but since I found a need for them, I have decided to add them. Referential integrity is probably valuable as well.
|
||||
|
||||
The need is that unlinking a channel and room using the web interface should clear up all related entries from `message_channel`, `event_message`, `reaction`, etc. Without foreign keys, this requires multiple DELETEs with tricky queries. With foreign keys and ON DELETE CASCADE, this just works.
|
||||
|
||||
## Quirks
|
||||
|
||||
* **REPLACE INTO** internally causes a DELETE followed by an INSERT, and the DELETE part **will trigger any ON DELETE CASCADE** foreign key conditions on the table, even when the primary key being replaced is the same.
|
||||
* ```sql
|
||||
CREATE TABLE discord_channel (channel_id TEXT NOT NULL, name TEXT NOT NULL, PRIMARY KEY (channel_id));
|
||||
CREATE TABLE discord_message (message_id TEXT NOT NULL, channel_id TEXT NOT NULL, PRIMARY KEY (message_id),
|
||||
FOREIGN KEY (channel_id) REFERENCES discord_channel (channel_id) ON DELETE CASCADE);
|
||||
INSERT INTO discord_channel (channel_id, name) VALUES ("c_1", "place");
|
||||
INSERT INTO discord_message (message_id, channel_id) VALUES ("m_2", "c_1"); -- i love my message
|
||||
REPLACE INTO discord_channel (channel_id, name) VALUES ("c_1", "new place"); -- replace into time
|
||||
-- i love my message
|
||||
SELECT * FROM discord_message; -- where is my message
|
||||
```
|
||||
* In SQLite, `pragma foreign_keys = on` must be set **for each connection** after it's established. I've added this at the start of `migrate.js`, which is called by all database connections.
|
||||
* Pragma? Pragma keys
|
||||
* Whenever a child row is inserted, SQLite will look up a row from the parent table to ensure referential integrity. This means **the parent table should be sufficiently keyed or indexed on columns referenced by foreign keys**, or SQLite won't let you do it, with a cryptic error message later on during DML. Due to normal forms, foreign keys naturally tend to reference the parent table's primary key, which is indexed, so that's okay. But still keep this in mind, since many of OOYE's tables effectively have two primary keys, for the Discord and Matrix IDs. A composite primary key doesn't count, even when it's the first column. A unique index counts.
|
||||
|
||||
## Where keys
|
||||
|
||||
Here are some tables that could potentially have foreign keys added between them, and my thought process of whether foreign keys would be a good idea:
|
||||
|
||||
* `guild_active` <--(PK guild_id FK)-- `channel_room` ✅
|
||||
* Could be good for referential integrity.
|
||||
* Linking to guild_space would be pretty scary in case the guild was being relinked to a different space - since rooms aren't tied to a space, this wouldn't actually disturb anything. So I pick guild_active instead.
|
||||
* `channel_room` <--(PK channel_id FK)-- `message_channel` ✅
|
||||
* Seems useful as we want message records to be deleted when a channel is unlinked.
|
||||
* `message_channel` <--(PK message_id PK)-- `event_message` ✅
|
||||
* Seems useful as we want event information to be deleted when a channel is unlinked.
|
||||
* `guild_active` <--(PK guild_id PK)-- `guild_space` ✅
|
||||
* All bridged guilds should have a corresponding guild_active entry, so referential integrity would be useful here to make sure we haven't got any weird states.
|
||||
* `channel_room` <--(**C** room_id PK)-- `member_cache` ✅
|
||||
* Seems useful as we want to clear the member cache when a channel is unlinked.
|
||||
* There is no index on `channel_room.room_id` right now. It would be good to create this index. Will just make it UNIQUE in the table definition.
|
||||
* `message_channel` <--(PK message_id FK)-- `reaction` ✅
|
||||
* Seems useful as we want to clear the reactions cache when a channel is unlinked.
|
||||
* `sim` <--(**C** mxid FK)-- `sim_member`
|
||||
* OOYE inner joins on this.
|
||||
* Sims are never deleted so if this was added it would only be used for enforcing referential integrity.
|
||||
* The storage cost of the additional index on `sim` would not be worth the benefits.
|
||||
* `channel_room` <--(**C** room_id PK)-- `sim_member`
|
||||
* If a room is being permanently unlinked, it may be useful to see a populated member list. If it's about to be relinked to another channel, we want to keep the sims in the room for more speed and to avoid spamming state events into the timeline.
|
||||
* Either way, the sims should remain in the room even after it's been unlinked. So no referential integrity is desirable here.
|
||||
* `sim` <--(PK user_id PK)-- `sim_proxy`
|
||||
* OOYE left joins on this. In normal operation, this relationship might not exist.
|
||||
* `channel_room` <--(PK channel_id PK)-- `webhook` ✅
|
||||
* Seems useful. Webhooks should be deleted from Discord just before the channel is unlinked. That should be mirrored in the database too.
|
||||
|
||||
## Occurrences of REPLACE INTO/DELETE FROM
|
||||
|
||||
* `edit-message.js` — `REPLACE INTO message_channel`
|
||||
* Scary! Changed to INSERT OR IGNORE
|
||||
* `send-message.js` — `REPLACE INTO message_channel`
|
||||
* Changed to INSERT OR IGNORE
|
||||
* `add-reaction.js` — `REPLACE INTO reaction`
|
||||
* `channel-webhook.js` — `REPLACE INTO webhook`
|
||||
* `send-event.js` — `REPLACE INTO message_channel`
|
||||
* Seems incorrect? Maybe?? Originally added in fcbb045. Changed to INSERT
|
||||
* `event-to-message.js` — `REPLACE INTO member_cache`
|
||||
* `oauth.js` — `REPLACE INTO guild_active`
|
||||
* Very scary!! Changed to INSERT .. ON CONFLICT DO UPDATE
|
||||
* `create-room.js` — `DELETE FROM channel_room`
|
||||
* Please cascade
|
||||
* `delete-message.js`
|
||||
* Removed redundant DELETEs
|
||||
* `edit-message.js` — `DELETE FROM event_message`
|
||||
* `register-pk-user.js` — `DELETE FROM sim`
|
||||
* It's a failsafe during creation
|
||||
* `register-user.js` — `DELETE FROM sim`
|
||||
* It's a failsafe during creation
|
||||
* `remove-reaction.js` — `DELETE FROM reaction`
|
||||
* `event-dispatcher.js` — `DELETE FROM member_cache`
|
||||
* `redact.js` — `DELETE FROM event_message`
|
||||
* Removed this redundant DELETE
|
||||
* `send-event.js` — `DELETE FROM event_message`
|
||||
* Removed this redundant DELETE
|
||||
|
||||
## How keys
|
||||
|
||||
SQLite does not have a complete ALTER TABLE command, so I have to DROP and CREATE. According to [the docs](https://www.sqlite.org/lang_altertable.html), the correct strategy is:
|
||||
|
||||
1. (Not applicable) *If foreign key constraints are enabled, disable them using PRAGMA foreign_keys=OFF.*
|
||||
2. Start a transaction.
|
||||
3. (Not applicable) *Remember the format of all indexes, triggers, and views associated with table X. This information will be needed in step 8 below. One way to do this is to run a query like the following: SELECT type, sql FROM sqlite_schema WHERE tbl_name='X'.*
|
||||
4. Use CREATE TABLE to construct a new table "new_X" that is in the desired revised format of table X. Make sure that the name "new_X" does not collide with any existing table name, of course.
|
||||
5. Transfer content from X into new_X using a statement like: INSERT INTO new_X SELECT ... FROM X.
|
||||
6. Drop the old table X: DROP TABLE X.
|
||||
7. Change the name of new_X to X using: ALTER TABLE new_X RENAME TO X.
|
||||
8. (Not applicable) *Use CREATE INDEX, CREATE TRIGGER, and CREATE VIEW to reconstruct indexes, triggers, and views associated with table X. Perhaps use the old format of the triggers, indexes, and views saved from step 3 above as a guide, making changes as appropriate for the alteration.*
|
||||
9. (Not applicable) *If any views refer to table X in a way that is affected by the schema change, then drop those views using DROP VIEW and recreate them with whatever changes are necessary to accommodate the schema change using CREATE VIEW.*
|
||||
10. If foreign key constraints were originally enabled then run PRAGMA foreign_key_check to verify that the schema change did not break any foreign key constraints.
|
||||
11. Commit the transaction started in step 2.
|
||||
12. (Not applicable) *If foreign keys constraints were originally enabled, reenable them now.*
|
|
@ -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) {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
BEGIN TRANSACTION;
|
||||
|
||||
INSERT INTO guild_space (guild_id, space_id, privacy_level) VALUES
|
||||
('112760669178241024', '!jjWAGMeQdNrVZSSfvz:cadence.moe', 0);
|
||||
|
||||
INSERT INTO guild_active (guild_id, autocreate) VALUES
|
||||
('112760669178241024', 1);
|
||||
|
||||
INSERT INTO guild_space (guild_id, space_id, privacy_level) VALUES
|
||||
('112760669178241024', '!jjWAGMeQdNrVZSSfvz:cadence.moe', 0);
|
||||
|
||||
INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom_avatar) VALUES
|
||||
('112760669178241024', '!kLRqKKUQXcibIMtOpl:cadence.moe', 'heave', 'main', NULL, NULL),
|
||||
('687028734322147344', '!fGgIymcYWOqjbSRUdV:cadence.moe', 'slow-news-day', NULL, NULL, NULL),
|
||||
('497161350934560778', '!CzvdIdUQXgUjDVKxeU:cadence.moe', 'amanda-spam', NULL, NULL, NULL),
|
||||
('160197704226439168', '!hYnGGlPHlbujVVfktC:cadence.moe', 'the-stanley-parable-channel', 'bots', NULL, NULL),
|
||||
('1100319550446252084', '!BnKuBPCvyfOkhcUjEu:cadence.moe', 'worm-farm', NULL, NULL, NULL),
|
||||
|
@ -18,25 +19,25 @@ INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom
|
|||
('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'),
|
||||
('820865262526005258', 'crunch_god', '_ooye_crunch_god', '@_ooye_crunch_god:cadence.moe'),
|
||||
('771520384671416320', 'bojack_horseman', '_ooye_bojack_horseman', '@_ooye_bojack_horseman:cadence.moe'),
|
||||
('112890272819507200', '.wing.', '_ooye_.wing.', '@_ooye_.wing.:cadence.moe'),
|
||||
('114147806469554185', 'extremity', '_ooye_extremity', '@_ooye_extremity:cadence.moe'),
|
||||
('111604486476181504', 'kyuugryphon', '_ooye_kyuugryphon', '@_ooye_kyuugryphon:cadence.moe'),
|
||||
('1109360903096369153', 'amanda', '_ooye_amanda', '@_ooye_amanda:cadence.moe'),
|
||||
('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '_pk_zoego', '_ooye__pk_zoego', '@_ooye__pk_zoego:cadence.moe'),
|
||||
('320067006521147393', 'papiophidian', '_ooye_papiophidian', '@_ooye_papiophidian:cadence.moe'),
|
||||
('772659086046658620', 'cadence', '_ooye_cadence', '@_ooye_cadence:cadence.moe');
|
||||
|
||||
INSERT INTO sim_proxy (user_id, proxy_owner_id, displayname) VALUES
|
||||
('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '196188877885538304', 'Azalea &flwr; 🌺');
|
||||
INSERT INTO sim (user_id, sim_name, mxid) VALUES
|
||||
('0', 'bot', '@_ooye_bot:cadence.moe'),
|
||||
('820865262526005258', 'crunch_god', '@_ooye_crunch_god:cadence.moe'),
|
||||
('771520384671416320', 'bojack_horseman', '@_ooye_bojack_horseman:cadence.moe'),
|
||||
('112890272819507200', '.wing.', '@_ooye_.wing.:cadence.moe'),
|
||||
('114147806469554185', 'extremity', '@_ooye_extremity:cadence.moe'),
|
||||
('111604486476181504', 'kyuugryphon', '@_ooye_kyuugryphon:cadence.moe'),
|
||||
('1109360903096369153', 'amanda', '@_ooye_amanda:cadence.moe'),
|
||||
('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '_pk_zoego', '@_ooye__pk_zoego:cadence.moe'),
|
||||
('320067006521147393', 'papiophidian', '@_ooye_papiophidian:cadence.moe'),
|
||||
('772659086046658620', 'cadence', '@_ooye_cadence:cadence.moe');
|
||||
|
||||
INSERT INTO sim_member (mxid, room_id, hashed_profile_content) VALUES
|
||||
('@_ooye_bojack_horseman:cadence.moe', '!hYnGGlPHlbujVVfktC:cadence.moe', NULL),
|
||||
('@_ooye_cadence:cadence.moe', '!BnKuBPCvyfOkhcUjEu:cadence.moe', NULL);
|
||||
|
||||
INSERT INTO sim_proxy (user_id, proxy_owner_id, displayname) VALUES
|
||||
('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '196188877885538304', 'Azalea &flwr; 🌺');
|
||||
|
||||
INSERT INTO message_channel (message_id, channel_id) VALUES
|
||||
('1106366167788044450', '122155380120748034'),
|
||||
('1106366167788044451', '122155380120748034'),
|
||||
|
@ -65,7 +66,8 @@ INSERT INTO message_channel (message_id, channel_id) VALUES
|
|||
('1273743950028607530', '1100319550446252084'),
|
||||
('1278002262400176128', '1100319550446252084'),
|
||||
('1278001833876525057', '1100319550446252084'),
|
||||
('1191567971970191490', '176333891320283136');
|
||||
('1191567971970191490', '176333891320283136'),
|
||||
('1144874214311067708', '687028734322147344');
|
||||
|
||||
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),
|
||||
|
@ -140,19 +142,16 @@ INSERT INTO emoji (emoji_id, name, animated, mxc_url) VALUES
|
|||
|
||||
INSERT INTO member_cache (room_id, mxid, displayname, avatar_url, power_level) VALUES
|
||||
('!kLRqKKUQXcibIMtOpl:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', NULL, 0),
|
||||
('!BpMdOUkWWhFxmTrENV:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'malformed mxc', 0),
|
||||
('!kLRqKKUQXcibIMtOpl:cadence.moe', '@test_auto_invite:example.org', NULL, NULL, 0),
|
||||
('!fGgIymcYWOqjbSRUdV:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU', 0),
|
||||
('!fGgIymcYWOqjbSRUdV:cadence.moe', '@rnl:cadence.moe', 'RNL', NULL, 0),
|
||||
('!BnKuBPCvyfOkhcUjEu:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU', 0),
|
||||
('!maggESguZBqGBZtSnr:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU', 0),
|
||||
('!BnKuBPCvyfOkhcUjEu:cadence.moe', '@ami:the-apothecary.club', 'Ami (she/her)', NULL, 0),
|
||||
('!CzvdIdUQXgUjDVKxeU:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU', 0),
|
||||
('!cBxtVRxDlZvSVhJXVK:cadence.moe', '@Milan:tchncs.de', 'Milan', NULL, 0),
|
||||
('!TqlyQmifxGUggEmdBN:cadence.moe', '@Milan:tchncs.de', 'Milan', NULL, 0),
|
||||
('!TqlyQmifxGUggEmdBN:cadence.moe', '@ampflower:matrix.org', 'Ampflower 🌺', 'mxc://cadence.moe/PRfhXYBTOalvgQYtmCLeUXko', 0),
|
||||
('!TqlyQmifxGUggEmdBN:cadence.moe', '@aflower:syndicated.gay', 'Rose', 'mxc://syndicated.gay/ZkBUPXCiXTjdJvONpLJmcbKP', 0),
|
||||
('!TqlyQmifxGUggEmdBN:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', NULL, 0),
|
||||
('!BnKuBPCvyfOkhcUjEu:cadence.moe', '@ami:the-apothecary.club', 'Ami (she/her)', NULL, 0),
|
||||
('!kLRqKKUQXcibIMtOpl:cadence.moe', '@test_auto_invite:example.org', NULL, NULL, 0),
|
||||
('!BpMdOUkWWhFxmTrENV:cadence.moe', '@test_auto_invite:example.org', NULL, NULL, 100);
|
||||
('!TqlyQmifxGUggEmdBN:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', NULL, 0);
|
||||
|
||||
INSERT INTO reaction (hashed_event_id, message_id, encoded_emoji) VALUES
|
||||
(5162930312280790092, '1141501302736695317', '%F0%9F%90%88');
|
||||
|
|
Loading…
Reference in a new issue