diff --git a/docs/self-service-room-creation-rules.md b/docs/self-service-room-creation-rules.md index 6292fe7..1638f09 100644 --- a/docs/self-service-room-creation-rules.md +++ b/docs/self-service-room-creation-rules.md @@ -63,8 +63,8 @@ Pressing buttons on web or using the /invite command on a guild will insert a ro So here's all the technical changes needed to support self-service in v3: -- New guild_active table showing whether, and how, a guild is bridged +- New guild_active table showing whether, and how, a guild is bridged. - When /invite command is used, INSERT OR IGNORE INTO state 1 and ensureRoom + ensureSpace. - When bot is added through "easy mode" web button, REPLACE INTO state 1 and ensureSpace. -- When bot is added through "self-service" web button, REPLACE INTO state 2. -- Event dispatcher will only ensureRoom if the guild_active state is 1 +- When bot is added through "self-service" web button, REPLACE INTO state 0. +- Event dispatcher will only ensureRoom if the guild_active state is 1. diff --git a/src/d2m/actions/create-room.js b/src/d2m/actions/create-room.js index 509d0ff..9be489b 100644 --- a/src/d2m/actions/create-room.js +++ b/src/d2m/actions/create-room.js @@ -279,6 +279,17 @@ function channelToGuild(channel) { return guild } +/** + * @param {string} channelID + * @param {string} guildID + */ +function existsOrAutocreatable(channelID, guildID) { + const existing = select("channel_room", ["room_id", "thread_parent"], {channel_id: channelID}).get() + if (existing) return existing + const autocreate = select("guild_active", "autocreate", {guild_id: guildID}).pluck().get() + return autocreate +} + /* Ensure flow: 1. Get IDs @@ -297,6 +308,7 @@ function channelToGuild(channel) { */ /** + * Create room and/or sync room data. Please check that a channel_room entry exists or autocreate = 1 before calling this. * @param {string} channelID * @param {boolean} shouldActuallySync false if just need to ensure room exists (which is a quick database check), true if also want to sync room data when it does exist (slow) * @returns {Promise} room ID @@ -311,9 +323,17 @@ async function _syncRoom(channelID, shouldActuallySync) { await inflightRoomCreate.get(channelID) // just waiting, and then doing a new db query afterwards, is the simplest way of doing it } - const existing = select("channel_room", ["room_id", "thread_parent"], {channel_id: channelID}).get() + const existing = existsOrAutocreatable(channelID, guild.id) + + if (existing === 0) { + throw new Error("refusing to create a new matrix room when autocreate is deactivated") + } if (!existing) { + throw new Error("refusing to craete a new matrix room when there is no guild_active entry") + } + + if (existing === 1) { const creation = (async () => { const {spaceID, privacyLevel, channelKState} = await channelToKState(channel, guild, {api}) const roomID = await createRoom(channel, guild, spaceID, channelKState, privacyLevel) @@ -353,12 +373,12 @@ async function _syncRoom(channelID, shouldActuallySync) { return roomID } -/** Ensures the room exists. If it doesn't, creates the room with an accurate initial state. */ +/** Ensures the room exists. If it doesn't, creates the room with an accurate initial state. Please check that a channel_room entry exists or guild autocreate = 1 before calling this. */ function ensureRoom(channelID) { return _syncRoom(channelID, false) } -/** Actually syncs. Gets all room state from the homeserver in order to diff, and uploads the icon to mxc if it has changed. */ +/** Actually syncs. Gets all room state from the homeserver in order to diff, and uploads the icon to mxc if it has changed. Please check that a channel_room entry exists or guild autocreate = 1 before calling this. */ function syncRoom(channelID) { return _syncRoom(channelID, true) } diff --git a/src/db/orm-defs.d.ts b/src/db/orm-defs.d.ts index 02003af..b1e6b79 100644 --- a/src/db/orm-defs.d.ts +++ b/src/db/orm-defs.d.ts @@ -35,7 +35,7 @@ export type Models = { guild_active: { guild_id: string - autocreate: number + autocreate: 0 | 1 } lottie: { diff --git a/src/discord/interactions/invite.js b/src/discord/interactions/invite.js index 689ea1a..ce80e99 100644 --- a/src/discord/interactions/invite.js +++ b/src/discord/interactions/invite.js @@ -4,6 +4,10 @@ const DiscordTypes = require("discord-api-types/v10") const assert = require("assert/strict") const {discord, sync, db, select, from} = require("../../passthrough") +/** @type {import("../../d2m/actions/create-room")} */ +const createRoom = sync.require("../../d2m/actions/create-room") +/** @type {import("../../d2m/actions/create-space")} */ +const createSpace = sync.require("../../d2m/actions/create-space") /** @type {import("../../matrix/api")} */ const api = sync.require("../../matrix/api") @@ -12,17 +16,6 @@ const api = sync.require("../../matrix/api") * @returns {Promise} */ async function _interact({data, channel, guild_id}) { - // Check guild is bridged - const spaceID = select("guild_space", "space_id", {guild_id}).pluck().get() - const roomID = select("channel_room", "room_id", {channel_id: channel.id}).pluck().get() - if (!spaceID || !roomID) return { - type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource, - data: { - content: "This server isn't bridged to Matrix, so you can't invite Matrix users.", - flags: DiscordTypes.MessageFlags.Ephemeral - } - } - // Get named MXID /** @type {DiscordTypes.APIApplicationCommandInteractionDataStringOption[] | undefined} */ // @ts-ignore const options = data.options @@ -36,6 +29,13 @@ async function _interact({data, channel, guild_id}) { } } + // Ensure guild and room are bridged + db.prepare("INSERT OR IGNORE INTO guild_active (guild_id, autocreate) VALUES (?, 1)").run(guild_id) + const roomID = await createRoom.ensureRoom(channel.id) + assert(roomID) + const spaceID = select("guild_space", "space_id", {guild_id}).pluck().get() + assert(spaceID) + // Check for existing invite to the space let spaceMember try {