mirror of
https://github.com/pacnpal/markov-discord.git
synced 2025-12-20 03:01:04 -05:00
Add select menu interaction for editing list of channels
This commit is contained in:
@@ -66,6 +66,11 @@ export const listenChannelCommand = new SlashCommandBuilder()
|
|||||||
sub
|
sub
|
||||||
.setName('list')
|
.setName('list')
|
||||||
.setDescription(`List the channels the bot is currently actively listening to.`)
|
.setDescription(`List the channels the bot is currently actively listening to.`)
|
||||||
|
)
|
||||||
|
.addSubcommand((sub) =>
|
||||||
|
sub
|
||||||
|
.setName('modify')
|
||||||
|
.setDescription(`Add or remove channels via select menu UI (first 25 text channels only)`)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const trainCommand = new SlashCommandBuilder()
|
export const trainCommand = new SlashCommandBuilder()
|
||||||
|
|||||||
104
src/index.ts
104
src/index.ts
@@ -11,8 +11,11 @@ import Markov, {
|
|||||||
|
|
||||||
import { createConnection } from 'typeorm';
|
import { createConnection } from 'typeorm';
|
||||||
import { MarkovInputData } from 'markov-strings-db/dist/src/entity/MarkovInputData';
|
import { MarkovInputData } from 'markov-strings-db/dist/src/entity/MarkovInputData';
|
||||||
import { APIInteractionGuildMember } from 'discord-api-types';
|
|
||||||
import type { PackageJsonPerson } from 'types-package-json';
|
import type { PackageJsonPerson } from 'types-package-json';
|
||||||
|
import {
|
||||||
|
APISelectMenuComponent,
|
||||||
|
APIInteractionGuildMember,
|
||||||
|
} from 'discord.js/node_modules/discord-api-types';
|
||||||
import L from './logger';
|
import L from './logger';
|
||||||
import { Channel } from './entity/Channel';
|
import { Channel } from './entity/Channel';
|
||||||
import { Guild } from './entity/Guild';
|
import { Guild } from './entity/Guild';
|
||||||
@@ -32,6 +35,12 @@ interface MarkovDataCustom {
|
|||||||
attachments: string[];
|
attachments: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SelectMenuChannel {
|
||||||
|
id: string;
|
||||||
|
listen?: boolean;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
const INVALID_PERMISSIONS_MESSAGE = 'You do not have the permissions for this action.';
|
const INVALID_PERMISSIONS_MESSAGE = 'You do not have the permissions for this action.';
|
||||||
const INVALID_GUILD_MESSAGE = 'This action must be performed within a server.';
|
const INVALID_GUILD_MESSAGE = 'This action must be performed within a server.';
|
||||||
|
|
||||||
@@ -77,6 +86,25 @@ async function getValidChannels(guild: Discord.Guild): Promise<Discord.TextChann
|
|||||||
return channels;
|
return channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getTextChannels(guild: Discord.Guild): Promise<SelectMenuChannel[]> {
|
||||||
|
const MAX_SELECT_OPTIONS = 25;
|
||||||
|
const textChannels = guild.channels.cache.filter(
|
||||||
|
(c): c is Discord.TextChannel => c !== null && c instanceof Discord.TextChannel
|
||||||
|
);
|
||||||
|
const foundDbChannels = await Channel.findByIds(Array.from(textChannels.keys()));
|
||||||
|
const foundDbChannelsWithName: SelectMenuChannel[] = foundDbChannels.map((c) => ({
|
||||||
|
...c,
|
||||||
|
name: textChannels.find((t) => t.id === c.id)?.name,
|
||||||
|
}));
|
||||||
|
const notFoundDbChannels: SelectMenuChannel[] = textChannels
|
||||||
|
.filter((c) => !foundDbChannels.find((d) => d.id === c.id))
|
||||||
|
.map((c) => ({ id: c.id, listen: false, name: textChannels.find((t) => t.id === c.id)?.name }));
|
||||||
|
const limitedDbChannels = foundDbChannelsWithName
|
||||||
|
.concat(notFoundDbChannels)
|
||||||
|
.slice(0, MAX_SELECT_OPTIONS);
|
||||||
|
return limitedDbChannels;
|
||||||
|
}
|
||||||
|
|
||||||
async function addValidChannels(channels: Discord.TextChannel[], guildId: string): Promise<void> {
|
async function addValidChannels(channels: Discord.TextChannel[], guildId: string): Promise<void> {
|
||||||
const dbChannels = channels.map((c) => {
|
const dbChannels = channels.map((c) => {
|
||||||
return Channel.create({ id: c.id, guild: Guild.create({ id: guildId }), listen: true });
|
return Channel.create({ id: c.id, guild: Guild.create({ id: guildId }), listen: true });
|
||||||
@@ -165,7 +193,7 @@ function messageToData(message: Discord.Message): AddDataProps {
|
|||||||
async function saveGuildMessageHistory(
|
async function saveGuildMessageHistory(
|
||||||
interaction: Discord.Message | Discord.CommandInteraction
|
interaction: Discord.Message | Discord.CommandInteraction
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
if (!isModerator(interaction.member as any)) return INVALID_PERMISSIONS_MESSAGE;
|
if (!isModerator(interaction.member)) return INVALID_PERMISSIONS_MESSAGE;
|
||||||
if (!interaction.guildId || !interaction.guild) return INVALID_GUILD_MESSAGE;
|
if (!interaction.guildId || !interaction.guild) return INVALID_GUILD_MESSAGE;
|
||||||
const markov = await getMarkovByGuildId(interaction.guildId);
|
const markov = await getMarkovByGuildId(interaction.guildId);
|
||||||
const channels = await getValidChannels(interaction.guild);
|
const channels = await getValidChannels(interaction.guild);
|
||||||
@@ -456,8 +484,7 @@ client.on('messageUpdate', async (oldMessage, newMessage) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
client.on('interactionCreate', async (interaction) => {
|
client.on('interactionCreate', async (interaction) => {
|
||||||
if (!interaction.isCommand()) return;
|
if (interaction.isCommand()) {
|
||||||
|
|
||||||
L.info({ command: interaction.commandName }, 'Recieved slash command');
|
L.info({ command: interaction.commandName }, 'Recieved slash command');
|
||||||
|
|
||||||
if (interaction.commandName === helpCommand.name) {
|
if (interaction.commandName === helpCommand.name) {
|
||||||
@@ -482,7 +509,7 @@ client.on('interactionCreate', async (interaction) => {
|
|||||||
const reply = await listValidChannels(interaction);
|
const reply = await listValidChannels(interaction);
|
||||||
await interaction.editReply(reply);
|
await interaction.editReply(reply);
|
||||||
} else if (subCommand === 'add') {
|
} else if (subCommand === 'add') {
|
||||||
if (!isModerator(interaction.member as any)) {
|
if (!isModerator(interaction.member)) {
|
||||||
await interaction.deleteReply();
|
await interaction.deleteReply();
|
||||||
await interaction.followUp({ content: INVALID_PERMISSIONS_MESSAGE, ephemeral: true });
|
await interaction.followUp({ content: INVALID_PERMISSIONS_MESSAGE, ephemeral: true });
|
||||||
return;
|
return;
|
||||||
@@ -493,7 +520,7 @@ client.on('interactionCreate', async (interaction) => {
|
|||||||
`Added ${channels.length} text channels to the list. Use \`/train\` to update the past known messages.`
|
`Added ${channels.length} text channels to the list. Use \`/train\` to update the past known messages.`
|
||||||
);
|
);
|
||||||
} else if (subCommand === 'remove') {
|
} else if (subCommand === 'remove') {
|
||||||
if (!isModerator(interaction.member as any)) {
|
if (!isModerator(interaction.member)) {
|
||||||
await interaction.deleteReply();
|
await interaction.deleteReply();
|
||||||
await interaction.followUp({ content: INVALID_PERMISSIONS_MESSAGE, ephemeral: true });
|
await interaction.followUp({ content: INVALID_PERMISSIONS_MESSAGE, ephemeral: true });
|
||||||
return;
|
return;
|
||||||
@@ -503,12 +530,77 @@ client.on('interactionCreate', async (interaction) => {
|
|||||||
await interaction.editReply(
|
await interaction.editReply(
|
||||||
`Removed ${channels.length} text channels from the list. Use \`/train\` to remove these channels from the past known messages.`
|
`Removed ${channels.length} text channels from the list. Use \`/train\` to remove these channels from the past known messages.`
|
||||||
);
|
);
|
||||||
|
} else if (subCommand === 'modify') {
|
||||||
|
await interaction.deleteReply();
|
||||||
|
if (!interaction.guild) {
|
||||||
|
await interaction.followUp({ content: INVALID_GUILD_MESSAGE, ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isModerator(interaction.member)) {
|
||||||
|
await interaction.followUp({ content: INVALID_PERMISSIONS_MESSAGE, ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const dbTextChannels = await getTextChannels(interaction.guild);
|
||||||
|
const row = new Discord.MessageActionRow().addComponents(
|
||||||
|
new Discord.MessageSelectMenu()
|
||||||
|
.setCustomId('listen-modify-select')
|
||||||
|
.setPlaceholder('Nothing selected')
|
||||||
|
.setMinValues(0)
|
||||||
|
.setMaxValues(dbTextChannels.length)
|
||||||
|
.addOptions(
|
||||||
|
dbTextChannels.map((c) => ({
|
||||||
|
label: `#${c.name}` || c.id,
|
||||||
|
value: c.id,
|
||||||
|
default: c.listen || false,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await interaction.followUp({
|
||||||
|
content: 'Select which channels you would like to the bot to actively listen to',
|
||||||
|
components: [row],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else if (interaction.commandName === trainCommand.name) {
|
} else if (interaction.commandName === trainCommand.name) {
|
||||||
await interaction.deferReply();
|
await interaction.deferReply();
|
||||||
const responseMessage = await saveGuildMessageHistory(interaction);
|
const responseMessage = await saveGuildMessageHistory(interaction);
|
||||||
await interaction.editReply(responseMessage);
|
await interaction.editReply(responseMessage);
|
||||||
}
|
}
|
||||||
|
} else if (interaction.isSelectMenu()) {
|
||||||
|
await interaction.deferUpdate();
|
||||||
|
const { guild } = interaction;
|
||||||
|
if (!isModerator(interaction.member)) {
|
||||||
|
await interaction.followUp({ content: INVALID_PERMISSIONS_MESSAGE, ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!guild) {
|
||||||
|
await interaction.deleteReply();
|
||||||
|
await interaction.followUp({ content: INVALID_GUILD_MESSAGE, ephemeral: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allChannels =
|
||||||
|
(interaction.component as APISelectMenuComponent).options?.map((o) => o.value) || [];
|
||||||
|
const selectedChannelIds = interaction.values;
|
||||||
|
|
||||||
|
const textChannels = (
|
||||||
|
await Promise.all(
|
||||||
|
allChannels.map(async (c) => {
|
||||||
|
return guild.channels.fetch(c);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).filter((c): c is Discord.TextChannel => c !== null && c instanceof Discord.TextChannel);
|
||||||
|
const unselectedChannels = textChannels.filter((t) => !selectedChannelIds.includes(t.id));
|
||||||
|
const selectedChannels = textChannels.filter((t) => selectedChannelIds.includes(t.id));
|
||||||
|
await addValidChannels(selectedChannels, guild.id);
|
||||||
|
await removeValidChannels(unselectedChannels, guild.id);
|
||||||
|
|
||||||
|
await interaction.followUp({
|
||||||
|
content: 'Updated actively listened to channels list.',
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user