Make the link button do something

This commit is contained in:
Cadence Ember 2024-10-18 16:35:47 +13:00
parent da5525a542
commit c127923f4d
3 changed files with 70 additions and 5 deletions

View file

@ -205,7 +205,7 @@ block body
p.s-description All of the above, and publicly visible in the Matrix space directory (like Server Discovery) p.s-description All of the above, and publicly visible in the Matrix space directory (like Server Discovery)
h3.mt32.fs-category Manually link channels h3.mt32.fs-category Manually link channels
form.d-flex.g16.ai-start(method="post" action="/api/link") form.d-flex.g16.ai-start(hx-post="/api/privacy-level" hx-trigger="submit" hx-disabled-elt="this")
.fl-grow2.s-btn-group.fd-column.w40 .fl-grow2.s-btn-group.fd-column.w40
each channel in unlinkedChannels each channel in unlinkedChannels
input.s-btn--radio(type="radio" name="discord" id=channel.id value=channel.id) input.s-btn--radio(type="radio" name="discord" id=channel.id value=channel.id)
@ -220,7 +220,8 @@ block body
+matrix(room, true) +matrix(room, true)
else else
.s-empty-state.p8 All Matrix rooms are linked. .s-empty-state.p8 All Matrix rooms are linked.
input(type="hidden" name="guild_id" value=guild_id)
div div
button.s-btn.s-btn__icon.s-btn__filled button.s-btn.s-btn__icon.s-btn__filled.htmx-indicator
!= icons.Icons.IconLink != icons.Icons.IconMerge
= ` Connect` = ` Link`

63
src/web/routes/link.js Normal file
View file

@ -0,0 +1,63 @@
// @ts-check
const {z} = require("zod")
const {defineEventHandler, useSession, createError, readValidatedBody} = require("h3")
const Ty = require("../../types")
const {discord, db, as, sync, select, from} = require("../../passthrough")
/** @type {import("../../d2m/actions/create-space")} */
const createSpace = sync.require("../../d2m/actions/create-space")
/** @type {import("../../d2m/actions/create-room")} */
const createRoom = sync.require("../../d2m/actions/create-room")
const {reg} = require("../../matrix/read-registration")
/** @type {import("../../matrix/api")} */
const api = sync.require("../../matrix/api")
const schema = {
link: z.object({
guild_id: z.string(),
matrix: z.string(),
discord: z.string()
})
}
as.router.post("/api/link", defineEventHandler(async event => {
const parsedBody = await readValidatedBody(event, schema.link.parse)
const session = await useSession(event, {password: reg.as_token})
// Check guild ID or nonce
const guildID = parsedBody.guild_id
if (!(session.data.managedGuilds || []).includes(guildID)) throw createError({status: 403, message: "Forbidden", data: "Can't edit a guild you don't have Manage Server permissions in"})
// Check guild is bridged
const guild = discord.guilds.get(guildID)
if (!guild) throw createError({status: 400, message: "Bad Request", data: "Discord guild does not exist or bot has not joined it"})
const spaceID = await createSpace.ensureSpace(guild)
// Check channel exists
const channel = discord.channels.get(parsedBody.discord)
if (!channel) throw createError({status: 400, message: "Bad Request", data: "Discord channel does not exist"})
// Check channel and room are not already bridged
const row = from("channel_room").select("channel_id", "room_id").and("WHERE channel_id = ? OR room_id = ?").get(parsedBody.discord, parsedBody.matrix)
if (row) throw createError({status: 400, message: "Bad Request", data: `Channel ID ${row.channel_id} and room ID ${row.room_id} are already bridged and cannot be reused`})
// Check room exists and bridge is joined and bridge has PL 100
const self = `@${reg.sender_localpart}:${reg.ooye.server_name}`
/** @type {Ty.Event.M_Room_Member} */
const memberEvent = await api.getStateEvent(parsedBody.matrix, "m.room.member", self)
if (memberEvent.membership !== "join") throw createError({status: 400, message: "Bad Request", data: "Matrix room does not exist"})
/** @type {Ty.Event.M_Power_Levels} */
const powerLevelsStateContent = await api.getStateEvent(parsedBody.matrix, "m.room.power_levels", "")
const selfPowerLevel = powerLevelsStateContent.users?.[self] || powerLevelsStateContent.users_default || 0
if (selfPowerLevel < (powerLevelsStateContent.state_default || 50) || selfPowerLevel < 100) throw createError({status: 400, message: "Bad Request", data: "OOYE needs power level 100 (admin) in the target Matrix room"})
// Insert database entry
db.prepare("INSERT INTO channel_room (channel_id, room_id, name, guild_id) VALUES (?, ?, ?, ?)").run(parsedBody.discord, parsedBody.matrix, channel.name, guildID)
// Sync room data and space child
createRoom.syncRoom(parsedBody.discord)
return null // 204
}))

View file

@ -23,8 +23,9 @@ pugSync.createRoute(as.router, "/ok", "ok.pug")
sync.require("./routes/download-matrix") sync.require("./routes/download-matrix")
sync.require("./routes/download-discord") sync.require("./routes/download-discord")
sync.require("./routes/invite")
sync.require("./routes/guild-settings") sync.require("./routes/guild-settings")
sync.require("./routes/invite")
sync.require("./routes/link")
sync.require("./routes/oauth") sync.require("./routes/oauth")
sync.require("./routes/qr") sync.require("./routes/qr")