Support multiple versions of rooms
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// @ts-check
|
||||
|
||||
const assert = require("assert")
|
||||
const assert = require("assert").strict
|
||||
|
||||
const passthrough = require("../../passthrough")
|
||||
const {discord, sync, db, select} = passthrough
|
||||
|
||||
@@ -228,7 +228,10 @@ async function createRoom(channel, guild, spaceID, kstate, privacyLevel) {
|
||||
...spaceCreationContent
|
||||
})
|
||||
|
||||
db.prepare("INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent) VALUES (?, ?, ?, NULL, ?)").run(channel.id, roomID, channel.name, threadParent)
|
||||
db.transaction(() => {
|
||||
db.prepare("INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent) VALUES (?, ?, ?, NULL, ?)").run(channel.id, roomID, channel.name, threadParent)
|
||||
db.prepare("INSERT INTO historical_channel_room (channel_id, room_id) VALUES (?, ?)").run(channel.id, roomID)
|
||||
})()
|
||||
|
||||
return roomID
|
||||
})
|
||||
@@ -400,7 +403,7 @@ async function _syncRoom(channelID, shouldActuallySync) {
|
||||
}
|
||||
const roomDiff = ks.diffKState(roomKState, channelKState)
|
||||
const roomApply = ks.applyKStateDiffToRoom(roomID, roomDiff)
|
||||
db.prepare("UPDATE channel_room SET name = ? WHERE room_id = ?").run(channel.name, roomID)
|
||||
db.prepare("UPDATE channel_room SET name = ? WHERE channel_id = ?").run(channel.name, channel.id)
|
||||
|
||||
// sync room as space member
|
||||
const spaceApply = _syncSpaceMember(channel, spaceID, roomID, guild.id)
|
||||
@@ -464,7 +467,7 @@ async function unbridgeDeletedChannel(channel, guildID) {
|
||||
|
||||
// delete room from database
|
||||
db.prepare("DELETE FROM member_cache WHERE room_id = ?").run(roomID)
|
||||
db.prepare("DELETE FROM channel_room WHERE room_id = ? AND channel_id = ?").run(roomID, channel.id) // cascades to most other tables, like messages
|
||||
db.prepare("DELETE FROM channel_room WHERE room_id = ? AND channel_id = ?").run(roomID, channel.id) // cascades to most other tables, like messages and historical rooms
|
||||
|
||||
if (!botInRoom) return
|
||||
|
||||
|
||||
@@ -14,11 +14,13 @@ async function deleteMessage(data) {
|
||||
const row = select("channel_room", ["room_id", "speedbump_checked", "thread_parent"], {channel_id: data.channel_id}).get()
|
||||
if (!row) return
|
||||
|
||||
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)
|
||||
for (const eventID of eventsToRedact) {
|
||||
// Assume we can redact from tombstoned rooms.
|
||||
const eventsToRedact = from("event_message").join("message_room", "message_id").join("historical_channel_room", "historical_room_index")
|
||||
.select("event_id", "room_id").where({message_id: data.id}).all()
|
||||
db.prepare("DELETE FROM message_room WHERE message_id = ?").run(data.id)
|
||||
for (const {event_id, room_id} 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)
|
||||
await api.redactEvent(room_id, event_id)
|
||||
}
|
||||
|
||||
await speedbump.updateCache(row.thread_parent || data.channel_id, row.speedbump_checked)
|
||||
@@ -28,15 +30,17 @@ async function deleteMessage(data) {
|
||||
* @param {import("discord-api-types/v10").GatewayMessageDeleteBulkDispatchData} data
|
||||
*/
|
||||
async function deleteMessageBulk(data) {
|
||||
const roomID = select("channel_room", "room_id", {channel_id: data.channel_id}).pluck().get()
|
||||
if (!roomID) return
|
||||
const row = select("channel_room", "room_id", {channel_id: data.channel_id}).get()
|
||||
if (!row) return
|
||||
|
||||
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)
|
||||
for (const eventID of eventsToRedact) {
|
||||
// Assume we can redact from tombstoned rooms.
|
||||
const eventsToRedact = from("event_message").join("message_room", "message_id").join("historical_channel_room", "historical_room_index")
|
||||
.select("event_id", "room_id").and("WHERE message_id IN (SELECT value FROM json_each(?))").all(sids)
|
||||
db.prepare("DELETE FROM message_room WHERE message_id IN (SELECT value FROM json_each(?))").run(sids)
|
||||
for (const {event_id, room_id} 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)
|
||||
await api.redactEvent(room_id, event_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
const assert = require("assert").strict
|
||||
|
||||
const passthrough = require("../../passthrough")
|
||||
const {sync, db, select} = passthrough
|
||||
const {sync, db, select, from} = passthrough
|
||||
/** @type {import("../converters/edit-to-changes")} */
|
||||
const editToChanges = sync.require("../converters/edit-to-changes")
|
||||
/** @type {import("./register-pk-user")} */
|
||||
@@ -19,6 +19,12 @@ const mreq = sync.require("../../matrix/mreq")
|
||||
* @param {{speedbump_id: string, speedbump_webhook_id: string} | null} row data about the webhook which is proxying messages in this channel
|
||||
*/
|
||||
async function editMessage(message, guild, row) {
|
||||
const historicalRoomOfMessage = from("message_room").join("historical_channel_room", "historical_room_index").where({message_id: message.id}).select("room_id").get()
|
||||
const currentRoom = from("channel_room").join("historical_channel_room", "room_id").where({channel_id: message.channel_id}).select("room_id", "historical_room_index").get()
|
||||
assert(currentRoom)
|
||||
|
||||
if (historicalRoomOfMessage && historicalRoomOfMessage.room_id !== currentRoom.room_id) return // tombstoned rooms should not have new events (including edits) sent to them
|
||||
|
||||
let {roomID, eventsToRedact, eventsToReplace, eventsToSend, senderMxid, promotions} = await editToChanges.editToChanges(message, guild, api)
|
||||
|
||||
if (row && row.speedbump_webhook_id === message.webhook_id) {
|
||||
@@ -61,7 +67,7 @@ async function editMessage(message, guild, row) {
|
||||
|
||||
// 4. Send all the things.
|
||||
if (eventsToSend.length) {
|
||||
db.prepare("INSERT OR IGNORE INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(message.id, message.channel_id)
|
||||
db.prepare("INSERT OR IGNORE INTO message_room (message_id, historical_room_index) VALUES (?, ?)").run(message.id, currentRoom.historical_room_index)
|
||||
}
|
||||
for (const content of eventsToSend) {
|
||||
const eventType = content.$type
|
||||
|
||||
@@ -4,10 +4,9 @@ const assert = require("assert").strict
|
||||
const {reg} = require("../../matrix/read-registration")
|
||||
const DiscordTypes = require("discord-api-types/v10")
|
||||
const Ty = require("../../types")
|
||||
const mixin = require("@cloudrac3r/mixin-deep")
|
||||
|
||||
const passthrough = require("../../passthrough")
|
||||
const {discord, sync, db, select} = passthrough
|
||||
const {discord, sync, db, from, select} = passthrough
|
||||
/** @type {import("../../matrix/api")} */
|
||||
const api = sync.require("../../matrix/api")
|
||||
/** @type {import("../../matrix/file")} */
|
||||
@@ -222,7 +221,8 @@ async function syncUser(user, member, channel, guild, roomID) {
|
||||
* @param {string} roomID
|
||||
*/
|
||||
async function syncAllUsersInRoom(roomID) {
|
||||
const mxids = select("sim_member", "mxid", {room_id: roomID}).pluck().all()
|
||||
const users = from("sim_member").join("sim", "mxid")
|
||||
.where({room_id: roomID}).and("and user_id not like '%-%' and user_id not like '%\\_%' escape '\\'").pluck("user_id").all()
|
||||
|
||||
const channelID = select("channel_room", "channel_id", {room_id: roomID}).pluck().get()
|
||||
assert.ok(typeof channelID === "string")
|
||||
@@ -234,10 +234,7 @@ async function syncAllUsersInRoom(roomID) {
|
||||
/** @ts-ignore @type {DiscordTypes.APIGuild} */
|
||||
const guild = discord.guilds.get(guildID)
|
||||
|
||||
for (const mxid of mxids) {
|
||||
const userID = select("sim", "user_id", {mxid}).pluck().get()
|
||||
assert.ok(typeof userID === "string")
|
||||
|
||||
for (const userID of users) {
|
||||
/** @ts-ignore @type {Required<DiscordTypes.APIGuildMember>} */
|
||||
const member = await discord.snow.guild.getGuildMember(guildID, userID)
|
||||
/** @ts-ignore @type {Required<DiscordTypes.APIUser>} user */
|
||||
|
||||
@@ -4,7 +4,7 @@ const Ty = require("../../types")
|
||||
const DiscordTypes = require("discord-api-types/v10")
|
||||
|
||||
const passthrough = require("../../passthrough")
|
||||
const {discord, sync, db, select} = passthrough
|
||||
const {discord, sync, db, from, select} = passthrough
|
||||
/** @type {import("../../matrix/api")} */
|
||||
const api = sync.require("../../matrix/api")
|
||||
/** @type {import("../converters/emoji-to-key")} */
|
||||
@@ -18,12 +18,15 @@ const converter = sync.require("../converters/remove-reaction")
|
||||
* @param {DiscordTypes.GatewayMessageReactionRemoveDispatchData | DiscordTypes.GatewayMessageReactionRemoveEmojiDispatchData | DiscordTypes.GatewayMessageReactionRemoveAllDispatchData} data
|
||||
*/
|
||||
async function removeSomeReactions(data) {
|
||||
const roomID = select("channel_room", "room_id", {channel_id: data.channel_id}).pluck().get()
|
||||
if (!roomID) return
|
||||
const eventIDForMessage = select("event_message", "event_id", {message_id: data.message_id, reaction_part: 0}).pluck().get()
|
||||
if (!eventIDForMessage) return
|
||||
const row = select("channel_room", "room_id", {channel_id: data.channel_id}).get()
|
||||
if (!row) return
|
||||
|
||||
const reactions = await api.getFullRelations(roomID, eventIDForMessage, "m.annotation")
|
||||
const eventReactedTo = from("event_message").join("message_room", "message_id").join("historical_channel_room", "historical_room_index")
|
||||
.where({message_id: data.message_id, reaction_part: 0}).select("event_id", "room_id").get()
|
||||
if (!eventReactedTo) return
|
||||
|
||||
// Due to server restrictions, all relations (i.e. reactions) have to be in the same room as the original event.
|
||||
const reactions = await api.getFullRelations(eventReactedTo.room_id, eventReactedTo.event_id, "m.annotation")
|
||||
|
||||
// Run the proper strategy and any strategy-specific database changes
|
||||
const removals = await
|
||||
@@ -33,7 +36,7 @@ async function removeSomeReactions(data) {
|
||||
|
||||
// Redact the events and delete individual stored events in the database
|
||||
for (const removal of removals) {
|
||||
await api.redactEvent(roomID, removal.eventID, removal.mxid)
|
||||
await api.redactEvent(eventReactedTo.room_id, removal.eventID, removal.mxid)
|
||||
if (removal.hash) db.prepare("DELETE FROM reaction WHERE hashed_event_id = ?").run(removal.hash)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ const dUtils = sync.require("../../discord/utils")
|
||||
*/
|
||||
async function sendMessage(message, channel, guild, row) {
|
||||
const roomID = await createRoom.ensureRoom(message.channel_id)
|
||||
const historicalRoomIndex = select("historical_channel_room", "historical_room_index", {room_id: roomID}).pluck().get()
|
||||
assert(historicalRoomIndex)
|
||||
|
||||
let senderMxid = null
|
||||
if (dUtils.isWebhookMessage(message)) {
|
||||
@@ -52,7 +54,7 @@ async function sendMessage(message, channel, guild, row) {
|
||||
const events = await messageToEvent.messageToEvent(message, guild, {}, {api, snow: discord.snow})
|
||||
const eventIDs = []
|
||||
if (events.length) {
|
||||
db.prepare("INSERT OR IGNORE INTO message_channel (message_id, channel_id) VALUES (?, ?)").run(message.id, message.channel_id)
|
||||
db.prepare("INSERT OR IGNORE INTO message_room (message_id, historical_room_index) VALUES (?, ?)").run(message.id, historicalRoomIndex)
|
||||
if (senderMxid) api.sendTyping(roomID, false, senderMxid).catch(() => {})
|
||||
}
|
||||
for (const event of events) {
|
||||
|
||||
Reference in New Issue
Block a user