Réécriture complète 4.0
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 6m16s
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 6m16s
This commit is contained in:
@@ -1,210 +1,241 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, ApplicationCommandOptionChoiceData, EmbedBuilder, inlineCode, PermissionFlagsBits } from 'discord.js'
|
||||
import dbGuild from '../../schemas/guild'
|
||||
import * as AMP from '../../utils/amp'
|
||||
|
||||
interface InstanceFields {
|
||||
name: string
|
||||
value: string
|
||||
inline: boolean
|
||||
}
|
||||
interface InstanceResult {
|
||||
status: string
|
||||
data: [
|
||||
Host
|
||||
]
|
||||
}
|
||||
interface Host {
|
||||
AvailableInstances: Instance[]
|
||||
FriendlyName: string
|
||||
}
|
||||
interface Instance {
|
||||
InstanceID: string
|
||||
FriendlyName: string
|
||||
Running: boolean
|
||||
Module: string
|
||||
Port: number
|
||||
}
|
||||
interface FailMsgData {
|
||||
Title: string
|
||||
Message: string
|
||||
}
|
||||
interface ErrorMsgData {
|
||||
error_code: string
|
||||
}
|
||||
|
||||
function failMsg(data: FailMsgData) { return `La commande a échouée !\n${inlineCode(`${data.Title}: ${data.Message}`)}` }
|
||||
function errorMsg(data: ErrorMsgData) { return `Y'a eu une erreur !\n${inlineCode(`${data.error_code}`)}` }
|
||||
|
||||
export default {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('amp')
|
||||
.setDescription('Accède à mon panel de jeu AMP !')
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
|
||||
.addSubcommand(subcommand => subcommand.setName('login').setDescription("Connectez-vous avant d'effectuer une autre commande !")
|
||||
.addStringOption(option => option.setName('username').setDescription("Nom d'Utilisateur").setRequired(true))
|
||||
.addStringOption(option => option.setName('password').setDescription('Mot de Passe').setRequired(true))
|
||||
.addBooleanOption(option => option.setName('remember').setDescription('Mémoriser les identifiants').setRequired(true))
|
||||
.addStringOption(option => option.setName('otp').setDescription('Code de double authentification')))
|
||||
.addSubcommandGroup(subcommandgroup => subcommandgroup.setName('instances').setDescription('Intéragir avec les instances AMP.')
|
||||
.addSubcommand(subcommand => subcommand.setName('list').setDescription('Liste toutes les instances disponibles.'))
|
||||
.addSubcommand(subcommand => subcommand.setName('manage').setDescription('Gérer une instance.')
|
||||
.addStringOption(option => option.setName('instance').setDescription("Nom de l'instance").setRequired(true).setAutocomplete(true)))
|
||||
.addSubcommand(subcommand => subcommand.setName('restart').setDescription('Redémarre une instance.')
|
||||
.addStringOption(option => option.setName('name').setDescription("Nom de l'instance").setRequired(true)))
|
||||
),
|
||||
async autocompleteRun(interaction: AutocompleteInteraction) {
|
||||
let query = interaction.options.getString('instance', true)
|
||||
|
||||
let guildProfile = await dbGuild.findOne({ guildId: interaction?.guild?.id })
|
||||
if (!guildProfile) return await interaction.respond([])
|
||||
|
||||
let dbData = guildProfile.get('guildAmp')
|
||||
if (!dbData?.enabled) return await interaction.respond([])
|
||||
|
||||
let host = dbData.host as string
|
||||
let username = dbData.username as string
|
||||
let sessionID = dbData.sessionID as string
|
||||
let rememberMeToken = dbData.rememberMeToken as string
|
||||
|
||||
// Check if the SessionID is still valid
|
||||
let session = await AMP.CheckSession(host, sessionID)
|
||||
if (session.status === 'fail') {
|
||||
if (rememberMeToken) {
|
||||
// Refresh the SessionID if the RememberMeToken is available
|
||||
let details = { username, password: '', token: rememberMeToken, rememberMe: true }
|
||||
let result = await AMP.Core.Login(host, details)
|
||||
|
||||
if (result.status === 'success') sessionID = result.data.sessionID
|
||||
else if (result.status === 'fail') return interaction.respond([])
|
||||
else if (result.status === 'error') return interaction.respond([])
|
||||
} else return await interaction.respond([])
|
||||
}
|
||||
else if (session.status === 'error') return interaction.respond([])
|
||||
|
||||
let choices: ApplicationCommandOptionChoiceData[] = []
|
||||
let result = await AMP.ADSModule.GetInstances(host, sessionID)
|
||||
if (result.status === 'success') {
|
||||
let hosts = result.data.result as Host[]
|
||||
hosts.forEach(host => {
|
||||
let instances = host.AvailableInstances as Instance[]
|
||||
instances.forEach(instance => {
|
||||
if (instance.FriendlyName.includes(query)) choices.push({ name: `${host.FriendlyName} - ${instance.FriendlyName}`, value: instance.InstanceID })
|
||||
})
|
||||
})
|
||||
}
|
||||
else if (result.status === 'fail') return interaction.respond([])
|
||||
else if (result.status === 'error') return interaction.respond([])
|
||||
|
||||
return interaction.respond(choices)
|
||||
},
|
||||
async execute(interaction: ChatInputCommandInteraction) {
|
||||
let guildProfile = await dbGuild.findOne({ guildId: interaction?.guild?.id })
|
||||
if (!guildProfile) return interaction.reply({ content: `Database data for **${interaction.guild?.name}** does not exist, please initialize with \`/database init\` !` })
|
||||
|
||||
let dbData = guildProfile.get('guildAmp')
|
||||
if (!dbData?.enabled) return interaction.reply({ content: `AMP module is disabled for **${interaction.guild?.name}**, please activate with \`/database edit guildAmp.enabled True\` !` })
|
||||
|
||||
let host = dbData.host as string
|
||||
let username = dbData.username as string
|
||||
let sessionID = dbData.sessionID as string
|
||||
let rememberMeToken = dbData.rememberMeToken as string
|
||||
|
||||
// Let the user login
|
||||
if (interaction.options.getSubcommand() == 'login') {
|
||||
// Get a SessionID and a RememberMeToken if wanted
|
||||
await interaction.deferReply({ ephemeral: true })
|
||||
|
||||
let details = {
|
||||
username: interaction.options.getString('username') || '',
|
||||
password: interaction.options.getString('password') || '',
|
||||
rememberMe: interaction.options.getBoolean('remember') || '',
|
||||
token: interaction.options.getString('otp') || ''
|
||||
}
|
||||
|
||||
let result = await AMP.Core.Login(host, details)
|
||||
if (result.status === 'success') {
|
||||
username = dbData['username'] = result.data.userInfo.Username
|
||||
sessionID = dbData['sessionID'] = result.data.sessionID
|
||||
rememberMeToken = dbData['rememberMeToken'] = result.data.rememberMeToken
|
||||
|
||||
guildProfile.set('guildAmp', dbData)
|
||||
guildProfile.markModified('guildAmp')
|
||||
await guildProfile.save().catch(console.error)
|
||||
|
||||
return await interaction.followUp(`Tu es connecté au panel sous **${username}** !`)
|
||||
}
|
||||
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data))
|
||||
else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data))
|
||||
}
|
||||
await interaction.deferReply()
|
||||
|
||||
// Check if the SessionID is still valid
|
||||
let session = await AMP.CheckSession(host, sessionID)
|
||||
if (session.status === 'fail') {
|
||||
if (rememberMeToken) {
|
||||
// Refresh the SessionID if the RememberMeToken is available
|
||||
let details = { username, password: '', token: rememberMeToken, rememberMe: true }
|
||||
let result = await AMP.Core.Login(host, details)
|
||||
|
||||
if (result.status === 'success') sessionID = result.data.sessionID
|
||||
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data))
|
||||
else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data))
|
||||
}
|
||||
else return await interaction.followUp(`Tu dois te connecter avant d'effectuer une autre commande !`)
|
||||
}
|
||||
else if (session.status === 'error') return await interaction.followUp(errorMsg(session.data))
|
||||
|
||||
if (interaction.options.getSubcommandGroup() == 'instances') {
|
||||
if (interaction.options.getSubcommand() == 'list') {
|
||||
let result = await AMP.ADSModule.GetInstances(host, sessionID) as InstanceResult
|
||||
|
||||
if (result.status === 'success') {
|
||||
await interaction.followUp({ content: `${result.data.length} hôte(s) trouvé(s) !` })
|
||||
result.data.forEach(async host => {
|
||||
let fields = [] as InstanceFields[]
|
||||
host.AvailableInstances.forEach((instance: Instance) => {
|
||||
fields.push({
|
||||
name: instance.FriendlyName,
|
||||
value: `**Running:** ${instance.Running}\n**Port:** ${instance.Port}\n**Module:** ${instance.Module}`,
|
||||
inline: true
|
||||
})
|
||||
})
|
||||
let embed = new EmbedBuilder()
|
||||
.setTitle(host.FriendlyName)
|
||||
.setDescription(`Liste des ${host.AvailableInstances.length} instances :`)
|
||||
.setColor(interaction.guild?.members.me?.displayColor || '#ffc370')
|
||||
.setTimestamp()
|
||||
.setFields(fields)
|
||||
return await interaction.followUp({ embeds: [embed] })
|
||||
})
|
||||
}
|
||||
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data as unknown as FailMsgData))
|
||||
else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data as unknown as ErrorMsgData))
|
||||
}
|
||||
else if (interaction.options.getSubcommand() == 'manage') {
|
||||
let instanceID = interaction.options.getString('instance', true)
|
||||
let result = await AMP.ADSModule.ManageInstance(host, sessionID, instanceID)
|
||||
|
||||
if (result.status === 'success') {
|
||||
let server = await AMP.ADSModule.Servers(host, sessionID, instanceID)
|
||||
|
||||
if (server.status === 'success') return await interaction.followUp(`Ok !`)
|
||||
else if (server.status === 'fail') return await interaction.followUp(failMsg(server.data))
|
||||
else if (server.status === 'error') return await interaction.followUp(errorMsg(server.data))
|
||||
}
|
||||
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data))
|
||||
else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data))
|
||||
}
|
||||
else if (interaction.options.getSubcommand() == 'restart') {
|
||||
let query = interaction.options.getString('name')
|
||||
if (!query) return
|
||||
|
||||
let result = await AMP.ADSModule.RestartInstance(host, sessionID, query)
|
||||
|
||||
if (result.status === 'success') return await interaction.followUp(`Ok !`)
|
||||
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data))
|
||||
else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
import { SlashCommandBuilder, EmbedBuilder, inlineCode, PermissionFlagsBits, MessageFlags } from "discord.js"
|
||||
import type { ChatInputCommandInteraction, AutocompleteInteraction, ApplicationCommandOptionChoiceData, Locale } from "discord.js"
|
||||
import * as AMP from "@/utils/amp"
|
||||
import type { Host, Instance, InstanceFields, InstanceResult, LoginSuccessData } from "@/types/amp"
|
||||
import type { ReturnMsgData } from "@/types"
|
||||
import type { GuildAmp } from "@/types/schemas"
|
||||
import dbGuild from "@/schemas/guild"
|
||||
import { t } from "@/utils/i18n"
|
||||
|
||||
function returnMsg(result: ReturnMsgData, locale: Locale) {
|
||||
if (result.status === "fail") return `${t(locale, "common.failed")}\n${inlineCode(`${result.Title}: ${result.Message}`)}`
|
||||
if (result.status === "error") return `${t(locale, "common.error_occurred")}\n${inlineCode(`${result.error_code}`)}`
|
||||
}
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName("amp")
|
||||
.setDescription("Access my AMP gaming panel")
|
||||
.setDescriptionLocalizations({ fr: "Accède à mon panel de jeu AMP" })
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName("login")
|
||||
.setDescription("Log in before performing another command")
|
||||
.setNameLocalizations({ fr: "connexion" })
|
||||
.setDescriptionLocalizations({ fr: "Connectez-vous avant d'effectuer une autre commande" })
|
||||
.addStringOption(option => option
|
||||
.setName("username")
|
||||
.setDescription("Username")
|
||||
.setNameLocalizations({ fr: "nom_utilisateur" })
|
||||
.setDescriptionLocalizations({ fr: "Nom d'utilisateur" })
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption(option => option
|
||||
.setName("password")
|
||||
.setDescription("Password")
|
||||
.setNameLocalizations({ fr: "mot_de_passe" })
|
||||
.setDescriptionLocalizations({ fr: "Mot de passe" })
|
||||
.setRequired(true)
|
||||
)
|
||||
.addBooleanOption(option => option
|
||||
.setName("remember")
|
||||
.setDescription("Remember credentials")
|
||||
.setNameLocalizations({ fr: "memoriser" })
|
||||
.setDescriptionLocalizations({ fr: "Mémoriser les identifiants" })
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption(option => option
|
||||
.setName("otp")
|
||||
.setDescription("Two-factor authentication code")
|
||||
.setNameLocalizations({ fr: "otp" })
|
||||
.setDescriptionLocalizations({ fr: "Code d'authentification à 2 facteurs" })
|
||||
)
|
||||
)
|
||||
.addSubcommandGroup(subcommandgroup => subcommandgroup
|
||||
.setName("instances")
|
||||
.setDescription("Interact with AMP instances")
|
||||
.setNameLocalizations({ fr: "instances" })
|
||||
.setDescriptionLocalizations({ fr: "Intéragir avec les instances AMP" })
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName("list")
|
||||
.setDescription("List all available instances")
|
||||
.setNameLocalizations({ fr: "liste" })
|
||||
.setDescriptionLocalizations({ fr: "Lister toutes les instances disponibles" })
|
||||
)
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName("manage")
|
||||
.setDescription("Manage an instance")
|
||||
.setNameLocalizations({ fr: "gerer" })
|
||||
.setDescriptionLocalizations({ fr: "Gérer une instance" })
|
||||
.addStringOption(option => option
|
||||
.setName("instance")
|
||||
.setDescription("Instance name")
|
||||
.setNameLocalizations({ fr: "instance" })
|
||||
.setDescriptionLocalizations({ fr: "Nom de l'instance" })
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
)
|
||||
)
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName("restart")
|
||||
.setDescription("Restart an instance")
|
||||
.setNameLocalizations({ fr: "redemarrer" })
|
||||
.setDescriptionLocalizations({ fr: "Redémarrer une instance" })
|
||||
.addStringOption(option => option
|
||||
.setName("name")
|
||||
.setDescription("Instance name")
|
||||
.setNameLocalizations({ fr: "nom" })
|
||||
.setDescriptionLocalizations({ fr: "Nom de l'instance" })
|
||||
.setRequired(true)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
export async function execute(interaction: ChatInputCommandInteraction) {
|
||||
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
|
||||
if (!guildProfile) return interaction.reply({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })
|
||||
|
||||
const dbData = guildProfile.get("guildAmp") as GuildAmp
|
||||
if (!dbData.enabled) return interaction.reply({ content: t(interaction.locale, "amp.module_disabled"), flags: MessageFlags.Ephemeral })
|
||||
|
||||
const host = dbData.host
|
||||
if (!host) return interaction.reply({ content: t(interaction.locale, "amp.host_not_configured"), flags: MessageFlags.Ephemeral })
|
||||
|
||||
let username = dbData.username
|
||||
let sessionID = dbData.sessionID
|
||||
let rememberMeToken = dbData.rememberMeToken
|
||||
|
||||
const subcommandGroup = interaction.options.getSubcommandGroup(false)
|
||||
const subcommand = interaction.options.getSubcommand(true)
|
||||
if (subcommand == "login") {
|
||||
// Get a SessionID and a RememberMeToken if wanted
|
||||
await interaction.deferReply({ flags: MessageFlags.Ephemeral })
|
||||
|
||||
const details = {
|
||||
username: interaction.options.getString("username", true),
|
||||
password: interaction.options.getString("password", true),
|
||||
token: interaction.options.getString("otp") ?? "",
|
||||
rememberMe: interaction.options.getBoolean("remember", true)
|
||||
}
|
||||
|
||||
const result = await AMP.Core.Login(host, details)
|
||||
if (result.status !== "success") return interaction.followUp({ content: returnMsg(result, interaction.locale), flags: MessageFlags.Ephemeral })
|
||||
|
||||
const loginData = result.data as LoginSuccessData
|
||||
username = dbData.username = loginData.userInfo.Username
|
||||
sessionID = dbData.sessionID = loginData.sessionID
|
||||
rememberMeToken = dbData.rememberMeToken = loginData.rememberMeToken
|
||||
|
||||
guildProfile.set("guildAmp", dbData)
|
||||
guildProfile.markModified("guildAmp")
|
||||
await guildProfile.save().catch(console.error)
|
||||
|
||||
return interaction.followUp({ content: t(interaction.locale, "amp.logged_in", { username }), flags: MessageFlags.Ephemeral })
|
||||
}
|
||||
await interaction.deferReply()
|
||||
|
||||
// Check if the SessionID is still valid
|
||||
if (!sessionID) return interaction.followUp({ content: t(interaction.locale, "amp.login_required"), flags: MessageFlags.Ephemeral })
|
||||
|
||||
const checkResult = await AMP.CheckSession(host, sessionID)
|
||||
if (checkResult.status === "fail") {
|
||||
if (rememberMeToken && username) {
|
||||
// Refresh the SessionID if the RememberMeToken is available
|
||||
const details = { username, password: "", token: rememberMeToken, rememberMe: true }
|
||||
const loginResult = await AMP.Core.Login(host, details)
|
||||
if (loginResult.status !== "success") return interaction.followUp({ content: returnMsg(loginResult, interaction.locale), flags: MessageFlags.Ephemeral })
|
||||
|
||||
const loginData = loginResult.data as LoginSuccessData
|
||||
sessionID = loginData.sessionID
|
||||
}
|
||||
else return interaction.followUp({ content: t(interaction.locale, "amp.login_required"), flags: MessageFlags.Ephemeral })
|
||||
}
|
||||
else if (checkResult.status === "error") return interaction.followUp({ content: returnMsg(checkResult, interaction.locale), flags: MessageFlags.Ephemeral })
|
||||
|
||||
if (subcommandGroup == "instances") {
|
||||
if (subcommand == "list") {
|
||||
const result = (await AMP.ADSModule.GetInstances(host, sessionID)) as InstanceResult
|
||||
if (result.status !== "success") return interaction.followUp({ content: returnMsg(result, interaction.locale), flags: MessageFlags.Ephemeral })
|
||||
|
||||
await interaction.followUp({ content: t(interaction.locale, "amp.hosts_found", { count: result.data.length }) })
|
||||
await Promise.all(result.data.map(async host => {
|
||||
const fields = [] as InstanceFields[]
|
||||
host.AvailableInstances.forEach((instance: Instance) => {
|
||||
fields.push({ name: instance.FriendlyName, value: `**${t(interaction.locale, "amp.running")}:** ${instance.Running}\n**${t(interaction.locale, "amp.port")}:** ${instance.Port}\n**${t(interaction.locale, "amp.module")}:** ${instance.Module}`, inline: true })
|
||||
})
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle(host.FriendlyName)
|
||||
.setDescription(t(interaction.locale, "amp.instance_list", { count: host.AvailableInstances.length }))
|
||||
.setColor(interaction.guild?.members.me?.displayColor ?? "#ffc370")
|
||||
.setTimestamp()
|
||||
.setFields(fields)
|
||||
return interaction.followUp({ embeds: [embed] })
|
||||
}))
|
||||
}
|
||||
else if (subcommand == "manage") {
|
||||
const instanceID = interaction.options.getString("instance", true)
|
||||
|
||||
const manageResult = await AMP.ADSModule.ManageInstance(host, sessionID, instanceID)
|
||||
if (manageResult.status !== "success") return interaction.followUp({ content: returnMsg(manageResult, interaction.locale), flags: MessageFlags.Ephemeral })
|
||||
|
||||
const serversResult = await AMP.ADSModule.Servers(host, sessionID, instanceID)
|
||||
if (serversResult.status !== "success") return interaction.followUp({ content: returnMsg(serversResult, interaction.locale), flags: MessageFlags.Ephemeral })
|
||||
|
||||
return interaction.followUp({ content: t(interaction.locale, "amp.manage_success") })
|
||||
}
|
||||
else if (subcommand == "restart") {
|
||||
const query = interaction.options.getString("name", true)
|
||||
|
||||
const restartResult = await AMP.ADSModule.RestartInstance(host, sessionID, query)
|
||||
if (restartResult.status !== "success") return interaction.followUp({ content: returnMsg(restartResult, interaction.locale), flags: MessageFlags.Ephemeral })
|
||||
|
||||
return interaction.followUp({ content: t(interaction.locale, "amp.restart_success") })
|
||||
}
|
||||
}
|
||||
}
|
||||
export async function autocompleteRun(interaction: AutocompleteInteraction) {
|
||||
const query = interaction.options.getString("instance", true)
|
||||
|
||||
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
|
||||
if (!guildProfile) return interaction.respond([])
|
||||
|
||||
const dbData = guildProfile.get("guildAmp") as GuildAmp
|
||||
if (!dbData.enabled) return interaction.respond([])
|
||||
|
||||
const host = dbData.host
|
||||
if (!host) return interaction.respond([])
|
||||
|
||||
let sessionID = dbData.sessionID
|
||||
if (!sessionID) return interaction.respond([])
|
||||
|
||||
const username = dbData.username
|
||||
const rememberMeToken = dbData.rememberMeToken
|
||||
|
||||
const checkResult = await AMP.CheckSession(host, sessionID)
|
||||
if (checkResult.status === "fail") {
|
||||
if (rememberMeToken && username) {
|
||||
// Refresh the SessionID if the RememberMeToken is available
|
||||
const details = { username, password: "", token: rememberMeToken, rememberMe: true }
|
||||
const loginResult = await AMP.Core.Login(host, details)
|
||||
if (loginResult.status !== "success") return interaction.respond([])
|
||||
|
||||
const loginData = loginResult.data as LoginSuccessData
|
||||
sessionID = loginData.sessionID
|
||||
}
|
||||
else return interaction.respond([])
|
||||
}
|
||||
else if (checkResult.status === "error") return interaction.respond([])
|
||||
|
||||
const instancesResult = (await AMP.ADSModule.GetInstances(host, sessionID)) as InstanceResult
|
||||
if (instancesResult.status !== "success") return interaction.respond([])
|
||||
|
||||
const choices: ApplicationCommandOptionChoiceData[] = []
|
||||
const hosts = instancesResult.data as Host[]
|
||||
hosts.forEach(host => {
|
||||
const instances = host.AvailableInstances
|
||||
instances.forEach(instance => {
|
||||
if (instance.FriendlyName.includes(query)) choices.push({ name: `${host.FriendlyName} - ${instance.FriendlyName}`, value: instance.InstanceID })
|
||||
})
|
||||
})
|
||||
|
||||
return interaction.respond(choices)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user