feat/add-unlink-space-button #63
5 changed files with 247 additions and 26 deletions
|
|
@ -459,12 +459,12 @@ async function unbridgeDeletedChannel(channel, guildID) {
|
||||||
const webhook = select("webhook", ["webhook_id", "webhook_token"], {channel_id: channel.id}).get()
|
const webhook = select("webhook", ["webhook_id", "webhook_token"], {channel_id: channel.id}).get()
|
||||||
if (webhook) {
|
if (webhook) {
|
||||||
await discord.snow.webhook.deleteWebhook(webhook.webhook_id, webhook.webhook_token)
|
await discord.snow.webhook.deleteWebhook(webhook.webhook_id, webhook.webhook_token)
|
||||||
db.prepare("DELETE FROM webhook WHERE channel_id = ?").run(channel.id)
|
await db.prepare("DELETE FROM webhook WHERE channel_id = ?").run(channel.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete room from database
|
// delete room from database
|
||||||
db.prepare("DELETE FROM member_cache WHERE room_id = ?").run(roomID)
|
await 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
|
await db.prepare("DELETE FROM channel_room WHERE room_id = ? AND channel_id = ?").run(roomID, channel.id) // cascades to most other tables, like messages
|
||||||
|
|
||||||
if (!botInRoom) return
|
if (!botInRoom) return
|
||||||
|
|
||||||
|
|
@ -507,6 +507,7 @@ async function unbridgeDeletedChannel(channel, guildID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// leave room
|
// leave room
|
||||||
|
await api.setUserPower(roomID, bot, 0)
|
||||||
await api.leaveRoom(roomID)
|
await api.leaveRoom(roomID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,13 +129,13 @@ block body
|
||||||
|
|
||||||
h3.mt32.fs-category Linked channels
|
h3.mt32.fs-category Linked channels
|
||||||
.s-card.bs-sm.p0
|
.s-card.bs-sm.p0
|
||||||
form.s-table-container(method="post" action=rel("/api/unlink") hx-confirm="Do you want to unlink these channels?\nIt may take a moment to clean up Matrix resources.")
|
form.s-table-container(method="post" action=rel("/api/unlink"))
|
||||||
input(type="hidden" name="guild_id" value=guild_id)
|
input(type="hidden" name="guild_id" value=guild_id)
|
||||||
table.s-table.s-table__bx-simple
|
table.s-table.s-table__bx-simple
|
||||||
each row in linkedChannelsWithDetails
|
each row in linkedChannelsWithDetails
|
||||||
tr
|
tr
|
||||||
td.w40: +discord(row.channel)
|
td.w40: +discord(row.channel)
|
||||||
td.p2: button.s-btn.s-btn__muted.s-btn__xs(name="channel_id" value=row.channel.id hx-post=rel("/api/unlink") hx-trigger="click" hx-disabled-elt="this")!= icons.Icons.IconLinkSm
|
td.p2: button.s-btn.s-btn__muted.s-btn__xs(name="channel_id" cx-prevent-default hx-post=rel("/api/unlink") hx-confirm="Do you want to unlink these channels?\nIt may take a moment to clean up Matrix resources." value=row.channel.id hx-indicator="this" hx-disabled-elt="this")!= icons.Icons.IconLinkSm
|
||||||
td: +matrix(row)
|
td: +matrix(row)
|
||||||
else
|
else
|
||||||
tr
|
tr
|
||||||
|
|
@ -176,6 +176,18 @@ block body
|
||||||
!= icons.Icons.IconMerge
|
!= icons.Icons.IconMerge
|
||||||
= ` Link`
|
= ` Link`
|
||||||
|
|
||||||
|
h3.mt32.fs-category Unlink server
|
||||||
|
form.s-card.d-flex.fd-row-reverse.gx24.pl24.ai-center(method="post" action=rel("/api/unlink-space"))
|
||||||
|
input(type="hidden" name="guild_id" value=guild.id)
|
||||||
|
.fl-grow1.s-prose.s-prose__sm.lh-xl
|
||||||
|
p.
|
||||||
|
Sick of this bridge, or just made a mistake? You can unlink the whole server and all its channels.#[br]
|
||||||
|
This may take a minute to process. Please be patient and wait until the page refreshes.
|
||||||
|
div
|
||||||
|
button.s-btn.s-btn__icon.s-btn__danger.s-btn__outlined(cx-prevent-default hx-post=rel("/api/unlink-space") hx-confirm="Do you want to unlink this server and all its channels?\nIt may take a minute to clean up Matrix resources." hx-indicator="this" hx-disabled-elt="this")
|
||||||
|
!= icons.Icons.IconUnsync
|
||||||
|
span.ml4= ` Unlink`
|
||||||
|
|
||||||
details.mt48
|
details.mt48
|
||||||
summary Debug room list
|
summary Debug room list
|
||||||
.d-grid.grid__2.gx24
|
.d-grid.grid__2.gx24
|
||||||
|
|
@ -196,7 +208,7 @@ block body
|
||||||
ul.my8.ml24
|
ul.my8.ml24
|
||||||
each row in removedWrongTypeChannels
|
each row in removedWrongTypeChannels
|
||||||
li: a(href=`https://discord.com/channels/${guild_id}/${row.id}`) (#{row.type}) #{row.name}
|
li: a(href=`https://discord.com/channels/${guild_id}/${row.id}`) (#{row.type}) #{row.name}
|
||||||
h3.mt24 Unavailable channels: Bridge can't access
|
h3.mt24 Unavailable channels: Discord bot can't access
|
||||||
.s-card.p0
|
.s-card.p0
|
||||||
ul.my8.ml24
|
ul.my8.ml24
|
||||||
each row in removedPrivateChannels
|
each row in removedPrivateChannels
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,13 @@ html(lang="en")
|
||||||
document.styleSheets[0].insertRule(t, document.styleSheets[0].cssRules.length)
|
document.styleSheets[0].insertRule(t, document.styleSheets[0].cssRules.length)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
//- Prevent default
|
||||||
|
script.
|
||||||
|
document.querySelectorAll("[cx-prevent-default]").forEach(e => {
|
||||||
|
e.addEventListener("click", event => {
|
||||||
|
event.preventDefault()
|
||||||
|
})
|
||||||
|
})
|
||||||
script(src=rel("/static/htmx.js"))
|
script(src=rel("/static/htmx.js"))
|
||||||
//- Error dialog
|
//- Error dialog
|
||||||
aside.s-modal#server-error(aria-hidden="true")
|
aside.s-modal#server-error(aria-hidden="true")
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ const auth = sync.require("../auth")
|
||||||
const mreq = sync.require("../../matrix/mreq")
|
const mreq = sync.require("../../matrix/mreq")
|
||||||
const {reg} = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
|
|
||||||
|
const me = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {H3Event} event
|
* @param {H3Event} event
|
||||||
* @returns {import("../../matrix/api")}
|
* @returns {import("../../matrix/api")}
|
||||||
|
|
@ -39,6 +41,33 @@ function getCreateSpace(event) {
|
||||||
return event.context.createSpace || sync.require("../../d2m/actions/create-space")
|
return event.context.createSpace || sync.require("../../d2m/actions/create-space")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {H3Event} event
|
||||||
|
* @param {string} channel_id
|
||||||
|
* @param {string} guild_id
|
||||||
|
*/
|
||||||
|
async function doRoomUnlink(event, channel_id, guild_id) {
|
||||||
|
const createRoom = getCreateRoom(event)
|
||||||
|
|
||||||
|
// Check that the channel (if it exists) is part of this guild
|
||||||
|
/** @type {any} */
|
||||||
|
let channel = discord.channels.get(channel_id)
|
||||||
|
if (channel) {
|
||||||
|
if (!("guild_id" in channel) || channel.guild_id !== guild_id) throw createError({status: 400, message: "Bad Request", data: `Channel ID ${channel_id} is not part of guild ${guild_id}`})
|
||||||
|
} else {
|
||||||
|
// Otherwise, if the channel isn't cached, it must have been deleted.
|
||||||
|
// There's no other authentication here - it's okay for anyone to unlink a deleted channel just by knowing its ID.
|
||||||
|
channel = {id: channel_id}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check channel is currently bridged
|
||||||
|
const row = select("channel_room", "channel_id", {channel_id: channel_id}).get()
|
||||||
|
if (!row) throw createError({status: 400, message: "Bad Request", data: `Channel ID ${channel_id} is not currently bridged`})
|
||||||
|
|
||||||
|
// Do it
|
||||||
|
await createRoom.unbridgeDeletedChannel(channel, guild_id)
|
||||||
|
}
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
linkSpace: z.object({
|
linkSpace: z.object({
|
||||||
guild_id: z.string(),
|
guild_id: z.string(),
|
||||||
|
|
@ -52,7 +81,10 @@ const schema = {
|
||||||
unlink: z.object({
|
unlink: z.object({
|
||||||
guild_id: z.string(),
|
guild_id: z.string(),
|
||||||
channel_id: z.string()
|
channel_id: z.string()
|
||||||
})
|
}),
|
||||||
|
unlinkSpace: z.object({
|
||||||
|
guild_id: z.string(),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
as.router.post("/api/link-space", defineEventHandler(async event => {
|
as.router.post("/api/link-space", defineEventHandler(async event => {
|
||||||
|
|
@ -87,7 +119,6 @@ as.router.post("/api/link-space", defineEventHandler(async event => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check bridge has PL 100
|
// Check bridge has PL 100
|
||||||
const me = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
|
||||||
/** @type {Ty.Event.M_Power_Levels?} */
|
/** @type {Ty.Event.M_Power_Levels?} */
|
||||||
let powerLevelsStateContent = null
|
let powerLevelsStateContent = null
|
||||||
try {
|
try {
|
||||||
|
|
@ -202,7 +233,6 @@ as.router.post("/api/link", defineEventHandler(async event => {
|
||||||
as.router.post("/api/unlink", defineEventHandler(async event => {
|
as.router.post("/api/unlink", defineEventHandler(async event => {
|
||||||
const {channel_id, guild_id} = await readValidatedBody(event, schema.unlink.parse)
|
const {channel_id, guild_id} = await readValidatedBody(event, schema.unlink.parse)
|
||||||
const managed = await auth.getManagedGuilds(event)
|
const managed = await auth.getManagedGuilds(event)
|
||||||
const createRoom = getCreateRoom(event)
|
|
||||||
|
|
||||||
// Check guild ID or nonce
|
// Check guild ID or nonce
|
||||||
if (!managed.has(guild_id)) throw createError({status: 403, message: "Forbidden", data: "Can't edit a guild you don't have Manage Server permissions in"})
|
if (!managed.has(guild_id)) throw createError({status: 403, message: "Forbidden", data: "Can't edit a guild you don't have Manage Server permissions in"})
|
||||||
|
|
@ -211,24 +241,48 @@ as.router.post("/api/unlink", defineEventHandler(async event => {
|
||||||
const guild = discord.guilds.get(guild_id)
|
const guild = discord.guilds.get(guild_id)
|
||||||
if (!guild) throw createError({status: 400, message: "Bad Request", data: "Discord guild does not exist or bot has not joined it"})
|
if (!guild) throw createError({status: 400, message: "Bad Request", data: "Discord guild does not exist or bot has not joined it"})
|
||||||
|
|
||||||
// Check that the channel (if it exists) is part of this guild
|
await doRoomUnlink(event, channel_id, guild_id)
|
||||||
/** @type {any} */
|
|
||||||
let channel = discord.channels.get(channel_id)
|
|
||||||
if (channel) {
|
|
||||||
if (!("guild_id" in channel) || channel.guild_id !== guild_id) throw createError({status: 400, message: "Bad Request", data: `Channel ID ${channel_id} is not part of guild ${guild_id}`})
|
|
||||||
} else {
|
|
||||||
// Otherwise, if the channel isn't cached, it must have been deleted.
|
|
||||||
// There's no other authentication here - it's okay for anyone to unlink a deleted channel just by knowing its ID.
|
|
||||||
channel = {id: channel_id}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check channel is currently bridged
|
|
||||||
const row = select("channel_room", "channel_id", {channel_id: channel_id}).get()
|
|
||||||
if (!row) throw createError({status: 400, message: "Bad Request", data: `Channel ID ${channel_id} is not currently bridged`})
|
|
||||||
|
|
||||||
// Do it
|
|
||||||
await createRoom.unbridgeDeletedChannel(channel, guild_id)
|
|
||||||
|
|
||||||
setResponseHeader(event, "HX-Refresh", "true")
|
setResponseHeader(event, "HX-Refresh", "true")
|
||||||
return null // 204
|
return null // 204
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
as.router.post("/api/unlink-space", defineEventHandler(async event => {
|
||||||
|
const {guild_id} = await readValidatedBody(event, schema.unlinkSpace.parse)
|
||||||
|
const managed = await auth.getManagedGuilds(event)
|
||||||
|
const api = getAPI(event)
|
||||||
|
|
||||||
|
// Check guild ID or nonce
|
||||||
|
if (!managed.has(guild_id)) throw createError({status: 403, message: "Forbidden", data: "Can't edit a guild you don't have Manage Server permissions in"})
|
||||||
|
|
||||||
|
// Check guild exists
|
||||||
|
const guild = discord.guilds.get(guild_id)
|
||||||
|
if (!guild) throw createError({status: 400, message: "Bad Request", data: "Discord guild does not exist or bot has not joined it"})
|
||||||
|
|
||||||
|
const spaceID = select("guild_space", "space_id", {guild_id: guild_id}).pluck().get()
|
||||||
|
if (!spaceID) {
|
||||||
|
throw createError({status: 400, message: "Bad Request", data: "Matrix space does not exist or bot has not linked it"})
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkedChannels = select("channel_room", ["channel_id", "room_id", "name", "nick"], {guild_id: guild_id}).all()
|
||||||
|
|
||||||
|
for (const channel of linkedChannels) {
|
||||||
|
await doRoomUnlink(event, channel.channel_id, guild_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const remainingLinkedChannels = select("channel_room", ["channel_id", "room_id", "name", "nick"], {guild_id: guild_id}).all()
|
||||||
|
if (remainingLinkedChannels.length !== 0) {
|
||||||
|
throw createError({status: 500, message: "Internal Server Error", data: "Some linked room still exists after trying to unlink all of them. Aborting the space unlinking..."})
|
||||||
|
}
|
||||||
|
|
||||||
|
await api.setUserPower(spaceID, me, 0)
|
||||||
|
await api.leaveRoom(spaceID)
|
||||||
|
|
||||||
|
await db.prepare("DELETE FROM guild_space WHERE guild_id=? AND space_id=?").run(guild_id, spaceID)
|
||||||
|
await db.prepare("DELETE FROM guild_active WHERE guild_id=?").run(guild_id)
|
||||||
|
await discord.snow.user.leaveGuild(guild_id)
|
||||||
|
|
|||||||
|
await db.prepare("DELETE FROM invite WHERE room_id=?").run(spaceID)
|
||||||
|
|
||||||
|
setResponseHeader(event, "HX-Redirect", "/")
|
||||||
|
return null
|
||||||
|
}))
|
||||||
|
|
|
||||||
|
|
@ -666,7 +666,9 @@ test("web unlink room: successfully calls unbridgeDeletedChannel when the channe
|
||||||
})
|
})
|
||||||
|
|
||||||
test("web unlink room: checks that the channel is bridged", async t => {
|
test("web unlink room: checks that the channel is bridged", async t => {
|
||||||
|
const row = db.prepare("SELECT * FROM channel_room WHERE channel_id = '665310973967597573'").get()
|
||||||
db.prepare("DELETE FROM channel_room WHERE channel_id = '665310973967597573'").run()
|
db.prepare("DELETE FROM channel_room WHERE channel_id = '665310973967597573'").run()
|
||||||
|
|
||||||
const [error] = await tryToCatch(() => router.test("post", "/api/unlink", {
|
const [error] = await tryToCatch(() => router.test("post", "/api/unlink", {
|
||||||
sessionData: {
|
sessionData: {
|
||||||
managedGuilds: ["665289423482519565"]
|
managedGuilds: ["665289423482519565"]
|
||||||
|
|
@ -677,4 +679,149 @@ test("web unlink room: checks that the channel is bridged", async t => {
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
t.equal(error.data, "Channel ID 665310973967597573 is not currently bridged")
|
t.equal(error.data, "Channel ID 665310973967597573 is not currently bridged")
|
||||||
|
|
||||||
|
db.prepare("INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom_avatar, last_bridged_pin_timestamp, speedbump_id, speedbump_checked, speedbump_webhook_id, guild_id, custom_topic) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(row.channel_id, row.room_id, row.name, row.nick, row.thread_parent, row.custom_avatar, row.last_bridged_pin_timestamp, row.speedbump_id, row.speedbump_checked, row.speedbump_webhook_id, row.guild_id, row.custom_topic)
|
||||||
|
cadence
commented
What is the purpose of this database operation? What is the purpose of this database operation?
Elliu
commented
The test deletes the row above, to test for checks. The test deletes the row above, to test for checks.
But as I added more tests below related to unlinking, if this is kept deleted, then this cause unwanted errors when trying to run following tests because of inconsistent DB. So I restored it before moving to next test.
|
|||||||
|
const new_row = db.prepare("SELECT * FROM channel_room WHERE channel_id = '665310973967597573'").get()
|
||||||
|
t.deepEqual(row, new_row)
|
||||||
|
})
|
||||||
|
|
||||||
|
// *****
|
||||||
|
|
||||||
|
test("web unlink space: access denied if not logged in to Discord", async t => {
|
||||||
|
const [error] = await tryToCatch(() => router.test("post", "/api/unlink-space", {
|
||||||
|
body: {
|
||||||
|
guild_id: "665289423482519565"
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
t.equal(error.data, "Can't edit a guild you don't have Manage Server permissions in")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("web unlink space: checks that guild exists", async t => {
|
||||||
|
const [error] = await tryToCatch(() => router.test("post", "/api/unlink-space", {
|
||||||
|
sessionData: {
|
||||||
|
managedGuilds: ["2"]
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
guild_id: "2"
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
t.equal(error.data, "Discord guild does not exist or bot has not joined it")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("web unlink space: checks that a space is linked to the guild before trying to unlink the space", async t => {
|
||||||
|
const row = db.prepare("SELECT * FROM guild_space WHERE guild_id = '665289423482519565'").get()
|
||||||
|
db.prepare("DELETE FROM guild_space WHERE guild_id = '665289423482519565'").run()
|
||||||
|
|
||||||
|
const [error] = await tryToCatch(() => router.test("post", "/api/unlink-space", {
|
||||||
|
sessionData: {
|
||||||
|
managedGuilds: ["665289423482519565"]
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
guild_id: "665289423482519565"
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
t.equal(error.data, "Matrix space does not exist or bot has not linked it")
|
||||||
|
|
||||||
|
db.prepare("INSERT INTO guild_space (guild_id, space_id, privacy_level, presence, url_preview) VALUES (?, ?, ?, ?, ?)").run(row.guild_id, row.space_id, row.privacy_level, row.presence, row.url_preview)
|
||||||
|
const new_row = db.prepare("SELECT * FROM guild_space WHERE guild_id = '665289423482519565'").get()
|
||||||
|
t.deepEqual(row, new_row)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("web unlink space: correctly abort unlinking if some linked channels remain after trying to unlink them all", async t => {
|
||||||
|
let unbridgedChannel = false
|
||||||
|
|
||||||
|
const [error] = await tryToCatch(() => router.test("post", "/api/unlink-space", {
|
||||||
|
sessionData: {
|
||||||
|
managedGuilds: ["665289423482519565"]
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
guild_id: "665289423482519565",
|
||||||
|
},
|
||||||
|
createRoom: {
|
||||||
|
async unbridgeDeletedChannel(channel, guildID) {
|
||||||
|
unbridgedChannel = true
|
||||||
|
t.equal(channel.id, "665310973967597573")
|
||||||
|
t.equal(guildID, "665289423482519565")
|
||||||
|
// Do not actually delete the link from DB, should trigger error later in check
|
||||||
|
}
|
||||||
|
},
|
||||||
|
api: {
|
||||||
|
async *generateFullHierarchy(spaceID) {
|
||||||
|
t.equal(spaceID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
||||||
|
yield {
|
||||||
|
room_id: "!NDbIqNpJyPvfKRnNcr:cadence.moe",
|
||||||
|
children_state: [],
|
||||||
|
guest_can_join: false,
|
||||||
|
num_joined_members: 2
|
||||||
|
}
|
||||||
|
/* c8 ignore next */
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
t.equal(error.data, "Some linked room still exists after trying to unlink all of them. Aborting the space unlinking...")
|
||||||
|
t.equal(unbridgedChannel, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("web unlink space: successfully calls unbridgeDeletedChannel on linked channels in space, self-downgrade power level, leave space, and delete link from DB", async t => {
|
||||||
|
const {reg} = require("../../matrix/read-registration")
|
||||||
|
const me = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
||||||
|
|
||||||
|
const getLinkRowQuery = "SELECT * FROM guild_space WHERE guild_id = '665289423482519565'"
|
||||||
|
|
||||||
|
const row = db.prepare(getLinkRowQuery).get()
|
||||||
|
t.equal(row.space_id, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
||||||
|
|
||||||
|
let unbridgedChannel = false
|
||||||
|
let downgradedPowerLevel = false
|
||||||
|
let leftRoom = false
|
||||||
|
await router.test("post", "/api/unlink-space", {
|
||||||
|
sessionData: {
|
||||||
|
managedGuilds: ["665289423482519565"]
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
guild_id: "665289423482519565",
|
||||||
|
},
|
||||||
|
createRoom: {
|
||||||
|
async unbridgeDeletedChannel(channel, guildID) {
|
||||||
|
unbridgedChannel = true
|
||||||
|
t.equal(channel.id, "665310973967597573")
|
||||||
|
t.equal(guildID, "665289423482519565")
|
||||||
|
|
||||||
|
// In order to not simulate channel deletion and not trigger the post unlink channels, pre-unlink space check
|
||||||
|
db.prepare("DELETE FROM channel_room WHERE guild_id = '665289423482519565' AND channel_id = '665310973967597573'").run()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
api: {
|
||||||
|
async *generateFullHierarchy(spaceID) {
|
||||||
|
t.equal(spaceID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
||||||
|
yield {
|
||||||
|
room_id: "!NDbIqNpJyPvfKRnNcr:cadence.moe",
|
||||||
|
children_state: [],
|
||||||
|
guest_can_join: false,
|
||||||
|
num_joined_members: 2
|
||||||
|
}
|
||||||
|
/* c8 ignore next */
|
||||||
|
},
|
||||||
|
|
||||||
|
async setUserPower(spaceID, targetUser, powerLevel) {
|
||||||
|
downgradedPowerLevel = true
|
||||||
|
t.equal(spaceID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
||||||
|
t.equal(targetUser, me)
|
||||||
|
t.equal(powerLevel, 0)
|
||||||
|
},
|
||||||
|
|
||||||
|
async leaveRoom(spaceID) {
|
||||||
|
leftRoom = true
|
||||||
|
t.equal(spaceID, "!zTMspHVUBhFLLSdmnS:cadence.moe")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.equal(unbridgedChannel, true)
|
||||||
|
t.equal(downgradedPowerLevel, true)
|
||||||
|
t.equal(leftRoom, true)
|
||||||
|
|
||||||
|
const missed_row = db.prepare(getLinkRowQuery).get()
|
||||||
|
t.equal(missed_row, undefined)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue
Also, this line causes issue when running the test.
I couldn't add the
snowmember likecreateRoomorapiin the test to add the function / member definition because it wasn't defined in the type, not really sure what's the best way to fix it