1
0
Fork 0

Add tests for privacy interaction

This commit is contained in:
Cadence Ember 2024-09-30 16:26:12 +13:00
parent f5853ccf95
commit f77602afa6
3 changed files with 122 additions and 14 deletions

View file

@ -3,32 +3,38 @@
const DiscordTypes = require("discord-api-types/v10") const DiscordTypes = require("discord-api-types/v10")
const {discord, sync, db, select} = require("../../passthrough") const {discord, sync, db, select} = require("../../passthrough")
const {id: botID} = require("../../../addbot") const {id: botID} = require("../../../addbot")
const {InteractionMethods} = require("snowtransfer")
/** @type {import("../../d2m/actions/create-space")} */ /** @type {import("../../d2m/actions/create-space")} */
const createSpace = sync.require("../../d2m/actions/create-space") const createSpace = sync.require("../../d2m/actions/create-space")
/** /**
* @param {DiscordTypes.APIChatInputApplicationCommandGuildInteraction} interaction * @param {DiscordTypes.APIChatInputApplicationCommandGuildInteraction} interaction
* @param {{createSpace: typeof createSpace}} di
* @returns {AsyncGenerator<{[k in keyof InteractionMethods]?: Parameters<InteractionMethods[k]>[2]}>}
*/ */
async function interact({id, token, data, guild_id}) { async function* _interact({data, guild_id}, {createSpace}) {
// Check guild is bridged // Check guild is bridged
const current = select("guild_space", "privacy_level", {guild_id}).pluck().get() const current = select("guild_space", "privacy_level", {guild_id}).pluck().get()
if (current == null) return { InteractionMethods.prototype.createInteractionResponse
if (current == null) {
return yield {createInteractionResponse: {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource, type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: { data: {
content: "This server isn't bridged to Matrix, so you can't set the Matrix privacy level.", content: "This server isn't bridged to Matrix, so you can't set the Matrix privacy level.",
flags: DiscordTypes.MessageFlags.Ephemeral flags: DiscordTypes.MessageFlags.Ephemeral
} }
}}
} }
// Get input level // Get input level
/** @type {DiscordTypes.APIApplicationCommandInteractionDataStringOption[] | undefined} */ // @ts-ignore /** @type {DiscordTypes.APIApplicationCommandInteractionDataStringOption[] | undefined} */ // @ts-ignore
const options = data.options const options = data.options
const input = options?.[0].value || "" const input = options?.[0]?.value || ""
const levels = ["invite", "link", "directory"] const levels = ["invite", "link", "directory"]
const level = levels.findIndex(x => input === x) const level = levels.findIndex(x => input === x)
if (level === -1) { if (level === -1) {
return discord.snow.interaction.createInteractionResponse(id, token, { return yield {createInteractionResponse: {
type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource, type: DiscordTypes.InteractionResponseType.ChannelMessageWithSource,
data: { data: {
content: "**Usage: `/privacy <level>`**. This will set who can join the space on Matrix-side. There are three levels:" content: "**Usage: `/privacy <level>`**. This will set who can join the space on Matrix-side. There are three levels:"
@ -38,22 +44,37 @@ async function interact({id, token, data, guild_id}) {
+ `\n**Current privacy level: \`${levels[current]}\`**`, + `\n**Current privacy level: \`${levels[current]}\`**`,
flags: DiscordTypes.MessageFlags.Ephemeral flags: DiscordTypes.MessageFlags.Ephemeral
} }
}) }}
} }
await discord.snow.interaction.createInteractionResponse(id, token, { yield {createInteractionResponse: {
type: DiscordTypes.InteractionResponseType.DeferredChannelMessageWithSource, type: DiscordTypes.InteractionResponseType.DeferredChannelMessageWithSource,
data: { data: {
flags: DiscordTypes.MessageFlags.Ephemeral flags: DiscordTypes.MessageFlags.Ephemeral
} }
}) }}
db.prepare("UPDATE guild_space SET privacy_level = ? WHERE guild_id = ?").run(level, guild_id) db.prepare("UPDATE guild_space SET privacy_level = ? WHERE guild_id = ?").run(level, guild_id)
await createSpace.syncSpaceFully(guild_id) // this is inefficient but OK to call infrequently on user request await createSpace.syncSpaceFully(guild_id) // this is inefficient but OK to call infrequently on user request
await discord.snow.interaction.editOriginalInteractionResponse(botID, token, { yield {editOriginalInteractionResponse: {
content: `Privacy level updated to \`${levels[level]}\`.` content: `Privacy level updated to \`${levels[level]}\`.`
}) }}
}
/* c8 ignore start */
/** @param {DiscordTypes.APIChatInputApplicationCommandGuildInteraction} interaction */
async function interact(interaction) {
for await (const response of _interact(interaction, {createSpace})) {
if (response.createInteractionResponse) {
// TODO: Test if it is reasonable to remove `await` from these calls. Or zip these calls with the next interaction iteration and use Promise.all.
await discord.snow.interaction.createInteractionResponse(interaction.id, interaction.token, response.createInteractionResponse)
} else if (response.editOriginalInteractionResponse) {
await discord.snow.interaction.editOriginalInteractionResponse(botID, interaction.token, response.editOriginalInteractionResponse)
}
}
} }
module.exports.interact = interact module.exports.interact = interact
module.exports._interact = _interact

View file

@ -0,0 +1,86 @@
const {test} = require("supertape")
const DiscordTypes = require("discord-api-types/v10")
const {select, db} = require("../../passthrough")
const {_interact} = require("./privacy")
/**
* @template T
* @param {AsyncIterable<T>} ai
* @returns {Promise<T[]>}
*/
async function fromAsync(ai) {
const result = []
for await (const value of ai) {
result.push(value)
}
return result
}
test("privacy: checks if guild is bridged", async t => {
const msgs = await fromAsync(_interact({
data: {
options: []
},
guild_id: "0"
}, {}))
t.equal(msgs.length, 1)
t.equal(msgs[0].createInteractionResponse.data.content, "This server isn't bridged to Matrix, so you can't set the Matrix privacy level.")
})
test("privacy: reports usage if there is no parameter", async t => {
const msgs = await fromAsync(_interact({
data: {
options: []
},
guild_id: "112760669178241024"
}, {}))
t.equal(msgs.length, 1)
t.match(msgs[0].createInteractionResponse.data.content, /Usage: `\/privacy/)
})
test("privacy: reports usage for invalid parameter", async t => {
const msgs = await fromAsync(_interact({
data: {
options: [
{
name: "level",
type: DiscordTypes.ApplicationCommandOptionType.String,
value: "info"
}
]
},
guild_id: "112760669178241024"
}, {}))
t.equal(msgs.length, 1)
t.match(msgs[0].createInteractionResponse.data.content, /Usage: `\/privacy/)
})
test("privacy: updates setting and calls syncSpace for valid parameter", async t => {
let called = 0
const msgs = await fromAsync(_interact({
data: {
options: [
{
name: "level",
type: DiscordTypes.ApplicationCommandOptionType.String,
value: "directory"
}
]
},
guild_id: "112760669178241024"
}, {
createSpace: {
async syncSpaceFully(guildID) {
called++
t.equal(guildID, "112760669178241024")
}
}
}))
t.equal(msgs.length, 2)
t.equal(msgs[0].createInteractionResponse.type, DiscordTypes.InteractionResponseType.DeferredChannelMessageWithSource)
t.equal(msgs[1].editOriginalInteractionResponse.content, "Privacy level updated to `directory`.")
t.equal(called, 1)
t.equal(select("guild_space", "privacy_level", {guild_id: "112760669178241024"}).pluck().get(), 2)
// Undo database changes
db.prepare("UPDATE guild_space SET privacy_level = 0 WHERE guild_id = ?").run("112760669178241024")
})

View file

@ -140,5 +140,6 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not
require("../src/m2d/converters/emoji-sheet.test") require("../src/m2d/converters/emoji-sheet.test")
require("../src/discord/interactions/invite.test") require("../src/discord/interactions/invite.test")
require("../src/discord/interactions/matrix-info.test") require("../src/discord/interactions/matrix-info.test")
require("../src/discord/interactions/privacy.test")
require("../src/discord/interactions/reactions.test") require("../src/discord/interactions/reactions.test")
})() })()