mirror of
https://github.com/tauri-apps/tauri-discord-bot.git
synced 2026-01-31 00:35:21 +01:00
Refactor thread command
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
import { command } from 'jellycommands';
|
||||
import { wrap_in_embed } from '../utils/embed_helpers';
|
||||
import { ChannelType, Message } from 'discord.js';
|
||||
import {
|
||||
AnyThreadChannel,
|
||||
Channel,
|
||||
ChannelType,
|
||||
ChatInputCommandInteraction,
|
||||
Collection,
|
||||
GuildTextBasedChannel,
|
||||
} from 'discord.js';
|
||||
import { HELP_THREAD_CHANNELS } from '../config';
|
||||
import { wrapErrors } from '../utils/errors';
|
||||
|
||||
export default command({
|
||||
name: 'threads',
|
||||
description: 'Manage all threads',
|
||||
|
||||
options: [
|
||||
{
|
||||
name: 'list',
|
||||
@@ -14,70 +20,88 @@ export default command({
|
||||
type: 'Subcommand',
|
||||
},
|
||||
],
|
||||
|
||||
global: true,
|
||||
defer: {
|
||||
ephemeral: true,
|
||||
},
|
||||
defer: { ephemeral: true },
|
||||
run: wrapErrors(async (interaction) => {
|
||||
const subcommand = interaction.options.getSubcommand(true);
|
||||
|
||||
run: async ({ interaction }) => {
|
||||
try {
|
||||
const subcommand = interaction.options.getSubcommand(true);
|
||||
// Get all active non-private threads in the guild that the user has access to
|
||||
const threads = (
|
||||
await interaction.guild.channels.fetchActiveThreads()
|
||||
).threads
|
||||
.map((x) => x)
|
||||
.filter((thread) =>
|
||||
thread
|
||||
.permissionsFor(interaction.user)
|
||||
.has(['ReadMessageHistory', 'ViewChannel']),
|
||||
);
|
||||
const activeThreads =
|
||||
await interaction.guild.channels.fetchActiveThreads();
|
||||
|
||||
switch (subcommand) {
|
||||
case 'list': {
|
||||
// Get the parent channel if we're using it inside a thread
|
||||
const parentChannel =
|
||||
interaction.channel.type === ChannelType.GuildText
|
||||
? interaction.channel
|
||||
: interaction.channel.parent;
|
||||
// Filter all threads based on the channel the command was ran in
|
||||
let listThreads = threads.filter(
|
||||
(thread) => thread.parentId === parentChannel.id,
|
||||
);
|
||||
if (HELP_THREAD_CHANNELS.includes(parentChannel.id)) {
|
||||
listThreads = listThreads.filter((thread) =>
|
||||
thread.name.startsWith('❔'),
|
||||
);
|
||||
}
|
||||
// Set a title for the DM
|
||||
let message = `**Here's a list of all currently active threads in <#${parentChannel.id}>**\n`;
|
||||
if (listThreads.length === 0) {
|
||||
message = `**There are currently no active threads in <#${parentChannel.id}>**`;
|
||||
} else {
|
||||
// Add all chat threads to the message
|
||||
message += listThreads
|
||||
.map((thread) => `<#${thread.id}>`)
|
||||
.join('\n');
|
||||
}
|
||||
// Send the message to the user
|
||||
await interaction.followUp(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Send the error
|
||||
const reply = (await interaction.followUp(
|
||||
wrap_in_embed((e as Error).message),
|
||||
)) as Message;
|
||||
// Delete the error after 15 seconds
|
||||
try {
|
||||
setTimeout(async () => {
|
||||
reply.delete();
|
||||
}, 15000);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
const visibleThreads = activeThreads.threads.filter((thread) =>
|
||||
thread
|
||||
.permissionsFor(interaction.user)
|
||||
.has(['ReadMessageHistory', 'ViewChannel']),
|
||||
);
|
||||
|
||||
switch (subcommand) {
|
||||
case 'list': {
|
||||
await handleList(interaction, visibleThreads);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
// If the channel is a text channel, it doesn't have a parent.
|
||||
// For other kinds of channels, we return null since it's not a thread.
|
||||
// If the channel is a thread, we return the parent channel.
|
||||
function getParentChannel(channel: GuildTextBasedChannel): Channel | null {
|
||||
switch (channel.type) {
|
||||
case ChannelType.GuildText:
|
||||
return channel;
|
||||
|
||||
case ChannelType.PublicThread:
|
||||
return channel.parent;
|
||||
|
||||
case ChannelType.PrivateThread:
|
||||
return channel.parent;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleList(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
visibleThreads: Collection<string, AnyThreadChannel<boolean>>,
|
||||
) {
|
||||
const parentChannel = getParentChannel(interaction.channel);
|
||||
if (!parentChannel) {
|
||||
return interaction.reply({
|
||||
ephemeral: true,
|
||||
content:
|
||||
'You can only use this command in a text channel or thread.',
|
||||
});
|
||||
}
|
||||
|
||||
if (!parentChannel.isTextBased()) {
|
||||
return interaction.reply({
|
||||
ephemeral: true,
|
||||
content: 'The parent of the thread must be a text channel.',
|
||||
});
|
||||
}
|
||||
|
||||
const isHelpChannel = HELP_THREAD_CHANNELS.includes(parentChannel.id);
|
||||
|
||||
const threadsWithinChannel = visibleThreads.filter(
|
||||
(thread) => thread.parentId === parentChannel.id,
|
||||
);
|
||||
|
||||
const threads = isHelpChannel
|
||||
? threadsWithinChannel
|
||||
: threadsWithinChannel.filter((thread) => thread.name.startsWith('❔'));
|
||||
|
||||
if (!threads.size) {
|
||||
return interaction.reply({
|
||||
ephemeral: true,
|
||||
content: `There are no active threads in <#${parentChannel.id}>.`,
|
||||
});
|
||||
}
|
||||
|
||||
const threadList = threads.map((thread) => `<#${thread.id}>`).join(', ');
|
||||
|
||||
await interaction.reply({
|
||||
content: `Active threads in <#${parentChannel.id}>: ${threadList}`,
|
||||
});
|
||||
}
|
||||
|
||||
18
src/utils/errors.ts
Normal file
18
src/utils/errors.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ChatInputCommandInteraction } from 'discord.js';
|
||||
|
||||
export function wrapErrors(
|
||||
handler: (interaction: ChatInputCommandInteraction) => Promise<void>,
|
||||
): (args: { interaction: ChatInputCommandInteraction }) => Promise<void> {
|
||||
return async ({ interaction }) => {
|
||||
try {
|
||||
await handler(interaction);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
await interaction.reply({
|
||||
content: `Runtime error: ${error}`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user