Add tests for privacy interaction
This commit is contained in:
parent
f5853ccf95
commit
f77602afa6
3 changed files with 122 additions and 14 deletions
|
@ -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
|
||||||
|
|
86
src/discord/interactions/privacy.test.js
Normal file
86
src/discord/interactions/privacy.test.js
Normal 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")
|
||||||
|
})
|
|
@ -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")
|
||||||
})()
|
})()
|
||||||
|
|
Loading…
Reference in a new issue