diff --git a/d2m/actions/create-room.js b/d2m/actions/create-room.js
index 2dd62e0..322f8be 100644
--- a/d2m/actions/create-room.js
+++ b/d2m/actions/create-room.js
@@ -120,7 +120,8 @@ async function channelToKState(channel, guild) {
if (customAvatar) {
avatarEventContent.url = customAvatar
} else if (guild.icon) {
- avatarEventContent.url = {$url: file.guildIcon(guild)}
+ avatarEventContent.discord_path = file.guildIcon(guild)
+ avatarEventContent.url = await file.uploadDiscordFileToMxc(avatarEventContent.discord_path) // TODO: somehow represent future values in kstate (callbacks?), while still allowing for diffing, so test cases don't need to touch the media API
}
let history_visibility = PRIVACY_ENUMS.ROOM_HISTORY_VISIBILITY[privacyLevel]
diff --git a/d2m/actions/create-space.js b/d2m/actions/create-space.js
index a9b8448..b15cba6 100644
--- a/d2m/actions/create-space.js
+++ b/d2m/actions/create-space.js
@@ -65,6 +65,7 @@ async function guildToKState(guild, privacyLevel) {
"m.room.name/": {name: guild.name},
"m.room.avatar/": {
$if: guild.icon,
+ discord_path: file.guildIcon(guild),
url: {$url: file.guildIcon(guild)}
},
"m.room.guest_access/": {guest_access: createRoom.PRIVACY_ENUMS.GUEST_ACCESS[privacyLevel]},
diff --git a/d2m/actions/create-space.test.js b/d2m/actions/create-space.test.js
index c4111db..b1c1f06 100644
--- a/d2m/actions/create-space.test.js
+++ b/d2m/actions/create-space.test.js
@@ -14,6 +14,7 @@ test("guild2space: can generate kstate for a guild, passing privacy level 0", as
await kstateUploadMxc(kstateStripConditionals(await guildToKState(testData.guild.general, 0))),
{
"m.room.avatar/": {
+ discord_path: "/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024",
url: "mxc://cadence.moe/zKXGZhmImMHuGQZWJEFKJbsF"
},
"m.room.guest_access/": {
diff --git a/d2m/converters/message-to-event.embeds.test.js b/d2m/converters/message-to-event.embeds.test.js
index 05e3b5d..61a0822 100644
--- a/d2m/converters/message-to-event.embeds.test.js
+++ b/d2m/converters/message-to-event.embeds.test.js
@@ -6,13 +6,6 @@ const Ty = require("../../types")
test("message2event embeds: nothing but a field", async t => {
const events = await messageToEvent(data.message_with_embeds.nothing_but_a_field, data.guild.general, {})
t.deepEqual(events, [{
- $type: "m.room.message",
- body: "> ↪️ @papiophidian: used `/stats`",
- format: "org.matrix.custom.html",
- formatted_body: "
↪️ @papiophidian used /stats
",
- "m.mentions": {},
- msgtype: "m.text",
- }, {
$type: "m.room.message",
"m.mentions": {},
msgtype: "m.notice",
@@ -150,13 +143,6 @@ test("message2event embeds: crazy html is all escaped", async t => {
test("message2event embeds: title without url", async t => {
const events = await messageToEvent(data.message_with_embeds.title_without_url, data.guild.general)
t.deepEqual(events, [{
- $type: "m.room.message",
- body: "> ↪️ @papiophidian: used `/stats`",
- format: "org.matrix.custom.html",
- formatted_body: "↪️ @papiophidian used /stats
",
- "m.mentions": {},
- msgtype: "m.text",
- }, {
$type: "m.room.message",
msgtype: "m.notice",
body: "| ## Hi, I'm Amanda!\n| \n| I condone pirating music!",
@@ -169,13 +155,6 @@ test("message2event embeds: title without url", async t => {
test("message2event embeds: url without title", async t => {
const events = await messageToEvent(data.message_with_embeds.url_without_title, data.guild.general)
t.deepEqual(events, [{
- $type: "m.room.message",
- body: "> ↪️ @papiophidian: used `/stats`",
- format: "org.matrix.custom.html",
- formatted_body: "↪️ @papiophidian used /stats
",
- "m.mentions": {},
- msgtype: "m.text",
- }, {
$type: "m.room.message",
msgtype: "m.notice",
body: "| I condone pirating music!",
@@ -188,13 +167,6 @@ test("message2event embeds: url without title", async t => {
test("message2event embeds: author without url", async t => {
const events = await messageToEvent(data.message_with_embeds.author_without_url, data.guild.general)
t.deepEqual(events, [{
- $type: "m.room.message",
- body: "> ↪️ @papiophidian: used `/stats`",
- format: "org.matrix.custom.html",
- formatted_body: "↪️ @papiophidian used /stats
",
- "m.mentions": {},
- msgtype: "m.text",
- }, {
$type: "m.room.message",
msgtype: "m.notice",
body: "| ## Amanda\n| \n| I condone pirating music!",
@@ -207,13 +179,6 @@ test("message2event embeds: author without url", async t => {
test("message2event embeds: author url without name", async t => {
const events = await messageToEvent(data.message_with_embeds.author_url_without_name, data.guild.general)
t.deepEqual(events, [{
- $type: "m.room.message",
- body: "> ↪️ @papiophidian: used `/stats`",
- format: "org.matrix.custom.html",
- formatted_body: "↪️ @papiophidian used /stats
",
- "m.mentions": {},
- msgtype: "m.text",
- }, {
$type: "m.room.message",
msgtype: "m.notice",
body: "| I condone pirating music!",
diff --git a/d2m/converters/message-to-event.js b/d2m/converters/message-to-event.js
index b86293e..1e77d9d 100644
--- a/d2m/converters/message-to-event.js
+++ b/d2m/converters/message-to-event.js
@@ -32,10 +32,7 @@ function getDiscordParseCallbacks(message, guild, useHTML) {
/** @param {{id: string, type: "discordUser"}} node */
user: node => {
const mxid = select("sim", "mxid", {user_id: node.id}).pluck().get()
- const interaction = message.interaction_metadata || message.interaction
- const username = message.mentions.find(ment => ment.id === node.id)?.username
- || (interaction?.user.id === node.id ? interaction.user.username : null)
- || node.id
+ const username = message.mentions.find(ment => ment.id === node.id)?.username || node.id
if (mxid && useHTML) {
return `@${username}`
} else {
@@ -232,13 +229,6 @@ async function messageToEvent(message, guild, options = {}, di) {
}]
}
- const interaction = message.interaction_metadata || message.interaction
- if (message.type === DiscordTypes.MessageType.ChatInputCommand && interaction && "name" in interaction) {
- // Commands are sent by the responding bot. Need to attach the metadata of the person using the command at the top.
- if (message.content) message.content = `\n${message.content}`
- message.content = `> ↪️ <@${interaction.user.id}> used \`/${interaction.name}\`${message.content}`
- }
-
/**
@type {{room?: boolean, user_ids?: string[]}}
We should consider the following scenarios for mentions:
@@ -373,7 +363,7 @@ async function messageToEvent(message, guild, options = {}, di) {
// Handling emojis that we don't know about. The emoji has to be present in the DB for it to be picked up in the emoji markdown converter.
// So we scan the message ahead of time for all its emojis and ensure they are in the DB.
- const emojiMatches = [...content.matchAll(/<(a?):([^:>]{1,64}):([0-9]+)>/g)]
+ const emojiMatches = [...content.matchAll(/<(a?):([^:>]{2,64}):([0-9]+)>/g)]
await Promise.all(emojiMatches.map(match => {
const id = match[3]
const name = match[2]
diff --git a/d2m/discord-client.js b/d2m/discord-client.js
index ace8481..80dcbcf 100644
--- a/d2m/discord-client.js
+++ b/d2m/discord-client.js
@@ -57,9 +57,6 @@ class DiscordClient {
addEventLogger("error", "Error")
addEventLogger("disconnected", "Disconnected")
addEventLogger("ready", "Ready")
- this.snow.requestHandler.on("requestError", (requestID, error) => {
- console.error("request error:", error)
- })
}
}
diff --git a/d2m/discord-packets.js b/d2m/discord-packets.js
index ed47fae..0981827 100644
--- a/d2m/discord-packets.js
+++ b/d2m/discord-packets.js
@@ -181,7 +181,7 @@ const utils = {
} catch (e) {
// Let OOYE try to handle errors too
- await eventDispatcher.onError(client, e, message)
+ eventDispatcher.onError(client, e, message)
}
}
}
diff --git a/d2m/event-dispatcher.js b/d2m/event-dispatcher.js
index 57cb72c..7f27b77 100644
--- a/d2m/event-dispatcher.js
+++ b/d2m/event-dispatcher.js
@@ -50,7 +50,7 @@ module.exports = {
* @param {Error} e
* @param {import("cloudstorm").IGatewayMessage} gatewayMessage
*/
- async onError(client, e, gatewayMessage) {
+ onError(client, e, gatewayMessage) {
console.error("hit event-dispatcher's error handler with this exception:")
console.error(e) // TODO: also log errors into a file or into the database, maybe use a library for this? or just wing it? definitely need to be able to store the formatted event body to load back in later
console.error(`while handling this ${gatewayMessage.t} gateway event:`)
@@ -83,7 +83,7 @@ module.exports = {
builder.addLine(`Error trace:\n${stackLines.join("\n")}`, `Error trace
${stackLines.join("\n")}
`)
}
builder.addLine("", `Original payload
${util.inspect(gatewayMessage.d, false, 4, false)}
`)
- await api.sendEvent(roomID, "m.room.message", {
+ api.sendEvent(roomID, "m.room.message", {
...builder.get(),
"moe.cadence.ooye.error": {
source: "discord",
diff --git a/db/orm-defs.d.ts b/db/orm-defs.d.ts
index 7484d76..e481f95 100644
--- a/db/orm-defs.d.ts
+++ b/db/orm-defs.d.ts
@@ -114,4 +114,3 @@ export type AllKeys = U extends any ? keyof U : never
export type PickTypeOf> = T extends { [k in K]?: any } ? T[K] : never
export type Merge = {[x in AllKeys]: PickTypeOf}
export type Nullable = {[k in keyof T]: T[k] | null}
-export type Numberish = {[k in keyof T]: T[k] extends number ? (number | bigint) : T[k]}
diff --git a/db/orm.js b/db/orm.js
index 601a7a0..09e4bc7 100644
--- a/db/orm.js
+++ b/db/orm.js
@@ -8,7 +8,7 @@ const U = require("./orm-defs")
* @template {keyof U.Models[Table]} Col
* @param {Table} table
* @param {Col[] | Col} cols
- * @param {Partial>} where
+ * @param {Partial} where
* @param {string} [e]
*/
function select(table, cols, where = {}, e = "") {
@@ -108,7 +108,7 @@ class From {
}
/**
- * @param {Partial>} conditions
+ * @param {Partial} conditions
*/
where(conditions) {
const wheres = Object.entries(conditions).map(([col, value]) => {
diff --git a/discord/interactions/bridge.js b/discord/interactions/bridge.js
index b2d1ac0..ee33bfd 100644
--- a/discord/interactions/bridge.js
+++ b/discord/interactions/bridge.js
@@ -39,7 +39,7 @@ async function getCachedHierarchy(spaceID) {
/** @type {{name: string, value: string}[]} */
const childRooms = []
for (const room of result) {
- if (room.name && !room.name.match(/^\[[⛓️🔊]\]/) && room.room_type !== "m.space") {
+ if (room.name) {
childRooms.push({name: room.name, value: room.room_id})
reverseCache.set(room.room_id, spaceID)
}
diff --git a/discord/interactions/invite.js b/discord/interactions/invite.js
index 689ea1a..0590be8 100644
--- a/discord/interactions/invite.js
+++ b/discord/interactions/invite.js
@@ -7,34 +7,31 @@ const {discord, sync, db, select, from} = require("../../passthrough")
/** @type {import("../../matrix/api")} */
const api = sync.require("../../matrix/api")
-/**
- * @param {DiscordTypes.APIChatInputApplicationCommandGuildInteraction} interaction
- * @returns {Promise}
- */
-async function _interact({data, channel, guild_id}) {
+/** @param {DiscordTypes.APIChatInputApplicationCommandGuildInteraction} interaction */
+async function interact({id, token, data, channel, member, 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 {
+ if (!spaceID || !roomID) return discord.snow.interaction.createInteractionResponse(id, token, {
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
const input = options?.[0].value || ""
const mxid = input.match(/@([^:]+):([a-z0-9:-]+\.[a-z0-9.:-]+)/)?.[0]
- if (!mxid) return {
+ if (!mxid) return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
content: "You have to say the Matrix ID of the person you want to invite. Matrix IDs look like this: `@username:example.org`",
flags: DiscordTypes.MessageFlags.Ephemeral
}
- }
+ })
// Check for existing invite to the space
let spaceMember
@@ -42,24 +39,24 @@ async function _interact({data, channel, guild_id}) {
spaceMember = await api.getStateEvent(spaceID, "m.room.member", mxid)
} catch (e) {}
if (spaceMember && spaceMember.membership === "invite") {
- return {
+ return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
content: `\`${mxid}\` already has an invite, which they haven't accepted yet.`,
flags: DiscordTypes.MessageFlags.Ephemeral
}
- }
+ })
}
// Invite Matrix user if not in space
if (!spaceMember || spaceMember.membership !== "join") {
await api.inviteToRoom(spaceID, mxid)
- return {
+ return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
content: `You invited \`${mxid}\` to the server.`
}
- }
+ })
}
// The Matrix user *is* in the space, maybe we want to invite them to this channel?
@@ -68,7 +65,7 @@ async function _interact({data, channel, guild_id}) {
roomMember = await api.getStateEvent(roomID, "m.room.member", mxid)
} catch (e) {}
if (!roomMember || (roomMember.membership !== "join" && roomMember.membership !== "invite")) {
- return {
+ return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
content: `\`${mxid}\` is already in this server. Would you like to additionally invite them to this specific channel?`,
@@ -83,49 +80,34 @@ async function _interact({data, channel, guild_id}) {
}]
}]
}
- }
+ })
}
// The Matrix user *is* in the space and in the channel.
- return {
+ return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
content: `\`${mxid}\` is already in this server and this channel.`,
flags: DiscordTypes.MessageFlags.Ephemeral
}
- }
+ })
}
-/**
- * @param {DiscordTypes.APIMessageComponentGuildInteraction} interaction
- * @returns {Promise}
- */
-async function _interactButton({channel, message}) {
+/** @param {DiscordTypes.APIMessageComponentGuildInteraction} interaction */
+async function interactButton({id, token, data, channel, member, guild_id, message}) {
const mxid = message.content.match(/`(@(?:[^:]+):(?:[a-z0-9:-]+\.[a-z0-9.:-]+))`/)?.[1]
assert(mxid)
const roomID = select("channel_room", "room_id", {channel_id: channel.id}).pluck().get()
await api.inviteToRoom(roomID, mxid)
- return {
+ return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.UpdateMessage,
data: {
content: `You invited \`${mxid}\` to the channel.`,
flags: DiscordTypes.MessageFlags.Ephemeral,
components: []
}
- }
-}
-
-/** @param {DiscordTypes.APIChatInputApplicationCommandGuildInteraction} interaction */
-async function interact(interaction) {
- await discord.snow.interaction.createInteractionResponse(interaction.id, interaction.token, await _interact(interaction))
-}
-
-/** @param {DiscordTypes.APIMessageComponentGuildInteraction} interaction */
-async function interactButton(interaction) {
- await discord.snow.interaction.createInteractionResponse(interaction.id, interaction.token, await _interactButton(interaction))
+ })
}
module.exports.interact = interact
module.exports.interactButton = interactButton
-module.exports._interact = _interact
-module.exports._interactButton = _interactButton
diff --git a/discord/interactions/matrix-info.js b/discord/interactions/matrix-info.js
index fac3804..9f0e9e1 100644
--- a/discord/interactions/matrix-info.js
+++ b/discord/interactions/matrix-info.js
@@ -7,8 +7,7 @@ const {discord, sync, db, select, from} = require("../../passthrough")
const api = sync.require("../../matrix/api")
/** @param {DiscordTypes.APIContextMenuGuildInteraction} interaction */
-/** @param {DiscordTypes.APIMessageApplicationCommandGuildInteraction} interaction */
-async function interact({id, token, guild_id, channel, data}) {
+async function interact({id, token, data}) {
const message = from("event_message").join("message_channel", "message_id").join("channel_room", "channel_id")
.select("name", "nick", "source", "room_id", "event_id").where({message_id: data.target_id}).get()
@@ -22,15 +21,12 @@ async function interact({id, token, guild_id, channel, data}) {
})
}
- const idInfo = `\n-# Room ID: \`${message.room_id}\`\n-# Event ID: \`${message.event_id}\``
-
if (message.source === 1) { // from Discord
- const userID = data.resolved.messages[data.target_id].author.id
return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
- content: `Bridged <@${userID}> https://discord.com/channels/${guild_id}/${channel.id}/${data.target_id} on Discord to [${message.nick || message.name}]() on Matrix.`
- + idInfo,
+ content: `This message was bridged to [${message.nick || message.name}]() on Matrix.`
+ + `\n-# Room ID: \`${message.room_id}\`\n-# Event ID: \`${message.event_id}\``,
flags: DiscordTypes.MessageFlags.Ephemeral
}
})
@@ -41,8 +37,9 @@ async function interact({id, token, guild_id, channel, data}) {
return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
- content: `Bridged [${event.sender}]()'s message in [${message.nick || message.name}]() on Matrix to https://discord.com/channels/${guild_id}/${channel.id}/${data.target_id} on Discord.`
- + idInfo,
+ content: `This message was bridged from [${message.nick || message.name}]() on Matrix.`
+ + `\nIt was originally sent by [${event.sender}]().`
+ + `\n-# Room ID: \`${message.room_id}\`\n-# Event ID: \`${message.event_id}\``,
flags: DiscordTypes.MessageFlags.Ephemeral
}
})
diff --git a/discord/interactions/permissions.js b/discord/interactions/permissions.js
index 82c3d3c..d30f632 100644
--- a/discord/interactions/permissions.js
+++ b/discord/interactions/permissions.js
@@ -5,27 +5,23 @@ const Ty = require("../../types")
const {discord, sync, db, select, from} = require("../../passthrough")
const assert = require("assert/strict")
-
/** @type {import("../../matrix/api")} */
const api = sync.require("../../matrix/api")
-/**
- * @param {DiscordTypes.APIContextMenuGuildInteraction} interaction
- * @returns {Promise}
- */
-async function _interact({data, channel, guild_id}) {
+/** @param {DiscordTypes.APIContextMenuGuildInteraction} interaction */
+async function interact({data, channel, id, token, guild_id}) {
const row = select("event_message", ["event_id", "source"], {message_id: data.target_id}).get()
assert(row)
// Can't operate on Discord users
if (row.source === 1) { // discord
- return {
+ return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
content: `This command is only meaningful for Matrix users.`,
flags: DiscordTypes.MessageFlags.Ephemeral
}
- }
+ })
}
// Get the message sender, the person that will be inspected/edited
@@ -46,16 +42,16 @@ async function _interact({data, channel, guild_id}) {
// Administrators equal to the bot cannot be demoted
if (userPower >= 100) {
- return {
+ return discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
content: `\`${sender}\` has administrator permissions. This cannot be edited.`,
flags: DiscordTypes.MessageFlags.Ephemeral
}
- }
+ })
}
- return {
+ await discord.snow.interaction.createInteractionResponse(id, token, {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: {
content: `Showing permissions for \`${sender}\`. Click to edit.`,
@@ -83,47 +79,30 @@ async function _interact({data, channel, guild_id}) {
}
]
}
- }
+ })
}
-/**
- * @param {DiscordTypes.APIMessageComponentSelectMenuInteraction} interaction
- */
-async function interactEdit({data, id, token, guild_id, message}) {
+/** @param {DiscordTypes.APIMessageComponentSelectMenuInteraction} interaction */
+async function interactEdit({data, channel, id, token, guild_id, message}) {
// Get the person that will be inspected/edited
const mxid = message.content.match(/`(@(?:[^:]+):(?:[a-z0-9:-]+\.[a-z0-9.:-]+))`/)?.[1]
assert(mxid)
- const permission = data.values[0]
- const power = permission === "moderator" ? 50 : 0
-
- await discord.snow.interaction.createInteractionResponse(id, token, {
- type: DiscordTypes.InteractionResponseType.UpdateMessage,
- data: {
- content: `Updating \`${mxid}\` to **${permission}**, please wait...`,
- components: []
- }
- })
-
// Get the space, where the power levels will be inspected/edited
const spaceID = select("guild_space", "space_id", {guild_id}).pluck().get()
assert(spaceID)
// Do it
- await api.setUserPowerCascade(spaceID, mxid, power)
+ const permission = data.values[0]
+ const power = permission === "moderator" ? 50 : 0
+ await api.setUserPower(spaceID, mxid, power)
+ // TODO: Cascade permissions through room hierarchy (make a helper for this already, geez...)
// ACK
- await discord.snow.interaction.editOriginalInteractionResponse(discord.application.id, token, {
- content: `Updated \`${mxid}\` to **${permission}**.`,
- components: []
+ await discord.snow.interaction.createInteractionResponse(id, token, {
+ type: DiscordTypes.InteractionResponseType.DeferredMessageUpdate
})
}
-/** @param {DiscordTypes.APIContextMenuGuildInteraction} interaction */
-async function interact(interaction) {
- await discord.snow.interaction.createInteractionResponse(interaction.id, interaction.token, await _interact(interaction))
-}
-
module.exports.interact = interact
module.exports.interactEdit = interactEdit
-module.exports._interact = _interact
diff --git a/discord/register-interactions.js b/discord/register-interactions.js
index a6e4332..79bcb14 100644
--- a/discord/register-interactions.js
+++ b/discord/register-interactions.js
@@ -48,23 +48,23 @@ discord.snow.interaction.bulkOverwriteApplicationCommands(id, [{
}])
async function dispatchInteraction(interaction) {
- const interactionId = interaction.data.custom_id || interaction.data.name
+ const id = interaction.data.custom_id || interaction.data.name
try {
console.log(interaction)
- if (interactionId === "Matrix info") {
+ if (id === "Matrix info") {
await matrixInfo.interact(interaction)
- } else if (interactionId === "invite") {
+ } else if (id === "invite") {
await invite.interact(interaction)
- } else if (interactionId === "invite_channel") {
+ } else if (id === "invite_channel") {
await invite.interactButton(interaction)
- } else if (interactionId === "Permissions") {
+ } else if (id === "Permissions") {
await permissions.interact(interaction)
- } else if (interactionId === "permissions_edit") {
+ } else if (id === "permissions_edit") {
await permissions.interactEdit(interaction)
- } else if (interactionId === "bridge") {
+ } else if (id === "bridge") {
await bridge.interact(interaction)
} else {
- throw new Error(`Unknown interaction ${interactionId}`)
+ throw new Error(`Unknown interaction ${id}`)
}
} catch (e) {
let stackLines = null
@@ -75,11 +75,14 @@ async function dispatchInteraction(interaction) {
stackLines = stackLines.slice(0, cloudstormLine - 2)
}
}
- await discord.snow.interaction.createFollowupMessage(id, interaction.token, {
- content: `Interaction failed: **${interactionId}**`
- + `\nError trace:\n\`\`\`\n${stackLines.join("\n")}\`\`\``
- + `Interaction data:\n\`\`\`\n${JSON.stringify(interaction.data, null, 2)}\`\`\``,
- flags: DiscordTypes.MessageFlags.Ephemeral
+ discord.snow.interaction.createInteractionResponse(interaction.id, interaction.token, {
+ type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
+ data: {
+ content: `Interaction failed: **${id}**`
+ + `\nError trace:\n\`\`\`\n${stackLines.join("\n")}\`\`\``
+ + `Interaction data:\n\`\`\`\n${JSON.stringify(interaction.data, null, 2)}\`\`\``,
+ flags: DiscordTypes.MessageFlags.Ephemeral
+ }
})
}
}
diff --git a/discord/utils.js b/discord/utils.js
index 865b2e3..57e563f 100644
--- a/discord/utils.js
+++ b/discord/utils.js
@@ -97,7 +97,8 @@ function hasAllPermissions(resolvedPermissions, permissionsToCheckFor) {
* @param {DiscordTypes.APIMessage} message
*/
function isWebhookMessage(message) {
- return message.webhook_id && message.type !== DiscordTypes.MessageType.ChatInputCommand
+ const isInteractionResponse = message.type === 20
+ return message.webhook_id && !isInteractionResponse
}
/**
diff --git a/m2d/actions/redact.js b/m2d/actions/redact.js
index ffbb261..7569df4 100644
--- a/m2d/actions/redact.js
+++ b/m2d/actions/redact.js
@@ -25,6 +25,7 @@ async function deleteMessage(event) {
*/
async function removeReaction(event) {
const hash = utils.getEventIDHash(event.redacts)
+ // TODO: this works but fix the type
const row = from("reaction").join("message_channel", "message_id").select("channel_id", "message_id", "encoded_emoji").where({hashed_event_id: hash}).get()
if (!row) return
await discord.snow.channel.deleteReactionSelf(row.channel_id, row.message_id, row.encoded_emoji)
diff --git a/matrix/api.js b/matrix/api.js
index e94a1a5..7d8ea9f 100644
--- a/matrix/api.js
+++ b/matrix/api.js
@@ -260,21 +260,6 @@ async function setUserPower(roomID, mxid, power) {
return powerLevels
}
-/**
- * Set a user's power level for a whole room hierarchy.
- * @param {string} roomID
- * @param {string} mxid
- * @param {number} power
- */
-async function setUserPowerCascade(roomID, mxid, power) {
- assert(roomID[0] === "!")
- assert(mxid[0] === "@")
- const rooms = await getFullHierarchy(roomID)
- for (const room of rooms) {
- await setUserPower(room.room_id, mxid, power)
- }
-}
-
module.exports.path = path
module.exports.register = register
module.exports.createRoom = createRoom
@@ -296,4 +281,3 @@ module.exports.sendTyping = sendTyping
module.exports.profileSetDisplayname = profileSetDisplayname
module.exports.profileSetAvatarUrl = profileSetAvatarUrl
module.exports.setUserPower = setUserPower
-module.exports.setUserPowerCascade = setUserPowerCascade
diff --git a/matrix/power.js b/matrix/power.js
index cd2b8cb..5dac550 100644
--- a/matrix/power.js
+++ b/matrix/power.js
@@ -1,6 +1,7 @@
// @ts-check
const {db, from} = require("../passthrough")
+const api = require("./api")
const reg = require("./read-registration")
const ks = require("./kstate")
const {applyKStateDiffToRoom, roomToKState} = require("../d2m/actions/create-room")
@@ -10,16 +11,13 @@ for (const mxid of reg.ooye.invite) {
db.prepare("INSERT OR IGNORE INTO member_power (mxid, room_id, power_level) VALUES (?, ?, 100)").run(mxid, "*")
}
-/** Apply global power level requests across ALL rooms where the member cache entry exists but the power level has not been applied yet. */
-function _getAffectedRooms() {
- return from("member_cache").join("member_power", "mxid")
- .and("where member_power.room_id = '*' and member_cache.power_level != member_power.power_level")
- .selectUnsafe("mxid", "member_cache.room_id", "member_power.power_level")
- .all()
-}
+// Apply global power level requests across ALL rooms where the member cache entry exists but the power level has not been applied yet.
+const rows = from("member_cache").join("member_power", "mxid")
+ .and("where member_power.room_id = '*' and member_cache.power_level != member_power.power_level")
+ .selectUnsafe("mxid", "member_cache.room_id", "member_power.power_level")
+ .all()
-async function applyPower() {
- const rows = _getAffectedRooms()
+;(async () => {
for (const row of rows) {
const kstate = await roomToKState(row.room_id)
const diff = ks.diffKState(kstate, {"m.room.power_levels/": {users: {[row.mxid]: row.power_level}}})
@@ -28,7 +26,4 @@ async function applyPower() {
// but we update it here anyway since the homeserver does not always deliver the event round-trip.
db.prepare("UPDATE member_cache SET power_level = ? WHERE room_id = ? AND mxid = ?").run(row.power_level, row.room_id, row.mxid)
}
-}
-
-module.exports._getAffectedRooms = _getAffectedRooms
-module.exports.applyPower = applyPower
+})()
diff --git a/start.js b/start.js
index 1ece1dd..63f5c57 100644
--- a/start.js
+++ b/start.js
@@ -25,14 +25,17 @@ const orm = sync.require("./db/orm")
passthrough.from = orm.from
passthrough.select = orm.select
-const power = require("./matrix/power.js")
sync.require("./m2d/event-dispatcher")
+discord.snow.requestHandler.on("requestError", data => {
+ console.error("request error", data)
+})
+
;(async () => {
await migrate.migrate(db)
await discord.cloud.connect()
console.log("Discord gateway started")
- await power.applyPower()
+ require("./matrix/power.js")
require("./stdin")
})()
diff --git a/test/data.js b/test/data.js
index 456033a..771c183 100644
--- a/test/data.js
+++ b/test/data.js
@@ -38,7 +38,8 @@ module.exports = {
}]
},
"m.room.avatar/": {
- url: {$url: "/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024"}
+ discord_path: "/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024",
+ url: "mxc://cadence.moe/zKXGZhmImMHuGQZWJEFKJbsF"
},
"m.room.power_levels/": {
events: {
diff --git a/test/ooye-test-data.sql b/test/ooye-test-data.sql
index 4666b4d..1fb9e24 100644
--- a/test/ooye-test-data.sql
+++ b/test/ooye-test-data.sql
@@ -23,8 +23,7 @@ INSERT INTO sim (user_id, sim_name, localpart, mxid) VALUES
('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');
+('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '_pk_zoego', '_ooye__pk_zoego', '@_ooye__pk_zoego:cadence.moe');
INSERT INTO sim_proxy (user_id, proxy_owner_id, displayname) VALUES
('43d378d5-1183-47dc-ab3c-d14e21c3fe58', '196188877885538304', 'Azalea &flwr; 🌺');
@@ -126,21 +125,19 @@ INSERT INTO emoji (emoji_id, name, animated, mxc_url) VALUES
('606664341298872324', 'online', 0, 'mxc://cadence.moe/LCEqjStXCxvRQccEkuslXEyZ'),
('288858540888686602', 'upstinky', 0, 'mxc://cadence.moe/mwZaCtRGAQQyOItagDeCocEO');
-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),
-('!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),
-('!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', '@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);
+INSERT INTO member_cache (room_id, mxid, displayname, avatar_url) VALUES
+('!kLRqKKUQXcibIMtOpl:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', NULL),
+('!BpMdOUkWWhFxmTrENV:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'malformed mxc'),
+('!fGgIymcYWOqjbSRUdV:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU'),
+('!fGgIymcYWOqjbSRUdV:cadence.moe', '@rnl:cadence.moe', 'RNL', NULL),
+('!BnKuBPCvyfOkhcUjEu:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU'),
+('!maggESguZBqGBZtSnr:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU'),
+('!CzvdIdUQXgUjDVKxeU:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', 'mxc://cadence.moe/azCAhThKTojXSZJRoWwZmhvU'),
+('!cBxtVRxDlZvSVhJXVK:cadence.moe', '@Milan:tchncs.de', 'Milan', NULL),
+('!TqlyQmifxGUggEmdBN:cadence.moe', '@ampflower:matrix.org', 'Ampflower 🌺', 'mxc://cadence.moe/PRfhXYBTOalvgQYtmCLeUXko'),
+('!TqlyQmifxGUggEmdBN:cadence.moe', '@aflower:syndicated.gay', 'Rose', 'mxc://syndicated.gay/ZkBUPXCiXTjdJvONpLJmcbKP'),
+('!TqlyQmifxGUggEmdBN:cadence.moe', '@cadence:cadence.moe', 'cadence [they]', NULL),
+('!BnKuBPCvyfOkhcUjEu:cadence.moe', '@ami:the-apothecary.club', 'Ami (she/her)', NULL);
INSERT INTO member_power (mxid, room_id, power_level) VALUES
('@test_auto_invite:example.org', '*', 100);
diff --git a/test/test.js b/test/test.js
index 796ff68..b5977f1 100644
--- a/test/test.js
+++ b/test/test.js
@@ -23,7 +23,6 @@ reg.ooye.server_name = "cadence.moe"
reg.id = "baby" // don't actually take authenticated actions on the server
reg.as_token = "baby"
reg.hs_token = "baby"
-reg.ooye.invite = []
const sync = new HeatSync({watchFS: false})
@@ -117,7 +116,6 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not
require("../matrix/kstate.test")
require("../matrix/api.test")
require("../matrix/file.test")
- require("../matrix/power.test")
require("../matrix/read-registration.test")
require("../matrix/txnid.test")
require("../d2m/actions/create-room.test")