Add //invite command

This commit is contained in:
Cadence Ember 2023-09-17 20:15:29 +12:00
parent 0ed74feb66
commit c9dec3ba75
3 changed files with 122 additions and 4 deletions

View file

@ -18,8 +18,8 @@ const createRoom = sync.require("./actions/create-room")
const createSpace = sync.require("./actions/create-space") const createSpace = sync.require("./actions/create-space")
/** @type {import("../matrix/api")}) */ /** @type {import("../matrix/api")}) */
const api = sync.require("../matrix/api") const api = sync.require("../matrix/api")
/** @type {import("./discord-command-handler")}) */ /** @type {import("../discord/discord-command-handler")}) */
const discordCommandHandler = sync.require("./discord-command-handler") const discordCommandHandler = sync.require("../discord/discord-command-handler")
let lastReportedEvent = 0 let lastReportedEvent = 0

View file

@ -10,6 +10,8 @@ const {discord, sync, db} = require("../passthrough")
const api = sync.require("../matrix/api") const api = sync.require("../matrix/api")
/** @type {import("../matrix/file")} */ /** @type {import("../matrix/file")} */
const file = sync.require("../matrix/file") const file = sync.require("../matrix/file")
/** @type {import("./utils")} */
const utils = sync.require("./utils")
const PREFIX = "//" const PREFIX = "//"
@ -121,9 +123,75 @@ const commands = [{
aliases: ["invite"], aliases: ["invite"],
execute: replyctx( execute: replyctx(
async (message, channel, guild, ctx) => { async (message, channel, guild, ctx) => {
return discord.snow.channel.createMessage(channel.id, { // Check guild is bridged
const spaceID = db.prepare("SELECT space_id FROM guild_space WHERE guild_id = ?").pluck().get(guild.id)
const roomID = db.prepare("SELECT room_id FROM channel_room WHERE channel_id = ?").pluck().get(channel.id)
if (!spaceID || !roomID) return discord.snow.channel.createMessage(channel.id, {
...ctx, ...ctx,
content: "This command isn't implemented yet." content: "This server isn't bridged to Matrix, so you can't invite Matrix users."
})
// Check CREATE_INSTANT_INVITE permission
assert(message.member)
const guildPermissions = utils.getPermissions(message.member.roles, guild.roles)
if (!(guildPermissions & BigInt(1))) {
return discord.snow.channel.createMessage(channel.id, {
...ctx,
content: "You don't have permission to invite people to this Discord server."
})
}
// Get named MXID
const mxid = message.content.match(/@([^:]+):([a-z0-9:-]+\.[a-z0-9.:-]+)/)?.[0]
if (!mxid) return discord.snow.channel.createMessage(channel.id, {
...ctx,
content: "You have to say the Matrix ID of the person you want to invite. Matrix IDs look like this: `@username:example.org`"
})
// Check for existing invite to the space
let spaceMember
try {
spaceMember = await api.getStateEvent(spaceID, "m.room.member", mxid)
} catch (e) {}
if (spaceMember && spaceMember.membership === "invite") {
return discord.snow.channel.createMessage(channel.id, {
...ctx,
content: `\`${mxid}\` already has an invite, which they haven't accepted yet.`
})
}
// Invite Matrix user if not in space
if (!spaceMember || spaceMember.membership !== "join") {
await api.inviteToRoom(spaceID, mxid)
return discord.snow.channel.createMessage(channel.id, {
...ctx,
content: `You invited \`${mxid}\` to the server.`
})
}
// The Matrix user *is* in the space, maybe we want to invite them to this channel?
let roomMember
try {
roomMember = await api.getStateEvent(roomID, "m.room.member", mxid)
} catch (e) {}
if (!roomMember || (roomMember.membership !== "join" && roomMember.membership !== "invite")) {
const sent = await discord.snow.channel.createMessage(channel.id, {
...ctx,
content: `\`${mxid}\` is already in this server. Would you like to additionally invite them to this specific channel?\nHit ✅ to make it happen.`
})
return addButton(channel.id, sent.id, "✅", message.author.id).then(async data => {
await api.inviteToRoom(roomID, mxid)
await discord.snow.channel.createMessage(channel.id, {
...ctx,
content: `You invited \`${mxid}\` to the channel.`
})
})
}
// The Matrix user *is* in the space and in the channel.
await discord.snow.channel.createMessage(channel.id, {
...ctx,
content: `\`${mxid}\` is already in this server and this channel.`
}) })
} }
) )

50
discord/utils.js Normal file
View file

@ -0,0 +1,50 @@
// @ts-check
const DiscordTypes = require("discord-api-types/v10")
/**
* @param {string[]} userRoles
* @param {DiscordTypes.APIGuild["roles"]} guildRoles
* @param {string} [userID]
* @param {DiscordTypes.APIGuildChannel["permission_overwrites"]} [channelOverwrites]
*/
function getPermissions(userRoles, guildRoles, userID, channelOverwrites) {
let allowed = BigInt(0)
let everyoneID
// Guild allows
for (const role of guildRoles) {
if (role.name === "@everyone") {
allowed |= BigInt(role.permissions)
everyoneID = role.id
}
if (userRoles.includes(role.id)) {
allowed |= BigInt(role.permissions)
}
}
if (channelOverwrites) {
/** @type {((overwrite: Required<DiscordTypes.APIGuildChannel>["permission_overwrites"][0]) => any)[]} */
const actions = [
// Channel @everyone deny
overwrite => overwrite.id === everyoneID && (allowed &= ~BigInt(overwrite.deny)),
// Channel @everyone allow
overwrite => overwrite.id === everyoneID && (allowed |= BigInt(overwrite.allow)),
// Role deny
overwrite => userRoles.includes(overwrite.id) && (allowed &= ~BigInt(overwrite.deny)),
// Role allow
overwrite => userRoles.includes(overwrite.id) && (allowed |= ~BigInt(overwrite.allow)),
// User deny
overwrite => overwrite.id === userID && (allowed &= ~BigInt(overwrite.deny)),
// User allow
overwrite => overwrite.id === userID && (allowed |= BigInt(overwrite.allow))
]
for (let i = 0; i < actions.length; i++) {
for (const overwrite of channelOverwrites) {
actions[i](overwrite)
}
}
}
return allowed
}
module.exports.getPermissions = getPermissions