Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feel free to ignore] Cleanup #140

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions src/commands/thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ export default command({
);
// Successfully solved the thread
// Get the first message in the thread
const start_message = await thread.fetchStarterMessage();
const start_message =
await thread.fetchStarterMessage();
// Get the first 2 messages after the start message
const messages = await thread.messages.fetch({
limit: 2,
Expand All @@ -167,7 +168,9 @@ export default command({
msg.components = [row];
await bot_message.edit(msg);
// Commands require a reply
await interaction.followUp(wrap_in_embed('Thread solved.'));
await interaction.followUp(
wrap_in_embed('Thread solved.'),
);
// Delete the reply after 10 seconds
setTimeout(async () => {
await interaction.deleteReply();
Expand All @@ -177,21 +180,33 @@ export default command({
if (!(thread.parent instanceof ForumChannel))
throw new Error("Can't solve a non-help channel");
// Parent forum channel
const solveChannel = thread.guild.channels.cache.get(thread.parentId) as ForumChannel
const solveChannel = thread.guild.channels.cache.get(
thread.parentId,
) as ForumChannel;
// Solve tag
const solveTag = solveChannel.availableTags.find(tag => tag.name === SOLVED_TAG).id
const solveTag = solveChannel.availableTags.find(
(tag) => tag.name === SOLVED_TAG,
).id;
// Unsolve tag
const unsolveTag = solveChannel.availableTags.find(tag => tag.name === UNSOLVED_TAG).id
const unsolveTag = solveChannel.availableTags.find(
(tag) => tag.name === UNSOLVED_TAG,
).id;
// If this is a ThreadChannel
let tags = thread.appliedTags.filter(tag => tag !== solveTag && tag !== unsolveTag).splice(0, 4)
let tags = thread.appliedTags
.filter((tag) => tag !== solveTag && tag !== unsolveTag)
.splice(0, 4);
// Add the solved tag
tags.unshift(solveTag)
tags.unshift(solveTag);
// If neither tag is going to exist in the channel, add unsolved
if (!tags.includes(solveTag) && !tags.includes(unsolveTag)) tags.unshift(unsolveTag)
if (!tags.includes(solveTag) && !tags.includes(unsolveTag))
tags.unshift(unsolveTag);
// Ensure no duplicates are in the array
tags = [...new Set(tags)].sort()
tags = [...new Set(tags)].sort();
// Apply tags
if (tags.toString() !== thread.appliedTags.sort().toString()) thread.setAppliedTags(tags)
if (
tags.toString() !== thread.appliedTags.sort().toString()
)
thread.setAppliedTags(tags);
// Commands require a reply
await interaction.followUp(wrap_in_embed('Thread solved.'));
// Delete the reply after 10 seconds
Expand Down
146 changes: 81 additions & 65 deletions src/commands/threads.ts
Original file line number Diff line number Diff line change
@@ -1,84 +1,100 @@
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',
description: 'List all open threads',
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.followUp({
ephemeral: true,
content:
'You can only use this command in a text channel or thread.',
});
}

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.followUp({
ephemeral: true,
content: `There are no active threads in <#${parentChannel.id}>.`,
});
}

const threadList = threads.map((thread) => `<#${thread.id}>`).join(', ');

await interaction.followUp({
content: `Active threads in <#${parentChannel.id}>: ${threadList}`,
});
}
114 changes: 57 additions & 57 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,94 +1,94 @@
export const DEV_MODE = process.env.NODE_ENV !== 'production';

export const GUILD_ID = DEV_MODE
? process.env.DEV_GUILD_ID
: '616186924390023171';
? process.env.DEV_GUILD_ID
: '616186924390023171';

export const DISCORD_TOKEN = process.env.DISCORD_TOKEN;

export const TAURI_BLUE = 0x67d6ed;

// people
const ADMIN_ROLES = DEV_MODE
? [process.env.DEV_ADMIN_ROLE]
: [
// admin
'985400380663935088',
// core
'616187491715907585',
// working-group
'761977421305610241',
];
? [process.env.DEV_ADMIN_ROLE]
: [
// admin
'985400380663935088',
// core
'616187491715907585',
// working-group
'761977421305610241',
];

// list of support roles without admin rights
export const HELPER_ROLES = DEV_MODE
? [process.env.DEV_HELPER_ROLE]
: [
// Helping Hand
'995034988699455609',
];
? [process.env.DEV_HELPER_ROLE]
: [
// Helping Hand
'995034988699455609',
];

export const BOT_DEVS = [
// LorenzoLewis
'402698003569180674',
// Simon
// '329752097530839041',
// LorenzoLewis
'402698003569180674',
// Simon
// '329752097530839041',
];

// list of roles/user IDs other than the creator allowed to modify threads
export const THREAD_ADMIN_IDS = [...ADMIN_ROLES, ...BOT_DEVS];

// auto thread channels with the issue handling feature
export const HELP_THREAD_CHANNELS = DEV_MODE
? [process.env.DEV_HELP_CHANNEL]
: [
// #help-triage
'625037620996734986',
];
? [process.env.DEV_HELP_CHANNEL]
: [
// #help-triage
'625037620996734986',
];

// channels that will be automatically threaded when a message is created
export const AUTO_THREAD_CHANNELS = DEV_MODE
? [process.env.DEV_DID_A_THING_CHANNEL, ...HELP_THREAD_CHANNELS]
: [
// #did-a-thing
'616234029842300930',
...HELP_THREAD_CHANNELS,
];
? [process.env.DEV_DID_A_THING_CHANNEL, ...HELP_THREAD_CHANNELS]
: [
// #did-a-thing
'616234029842300930',
...HELP_THREAD_CHANNELS,
];

export const MESSAGE_READ = '✅';

export const REACTION_ROLE: {
emojiName: string;
emojiId: string;
roleId: string;
description: string;
emojiName: string;
emojiId: string;
roleId: string;
description: string;
}[] = DEV_MODE
? [
{
emojiName: 'sausageroll',
emojiId: '995712110925451324',
roleId: process.env.DEV_REACTION_ROLE,
description:
'Join the conversation in the contributors channels (you can still view without this role)',
},
]
: [
{
emojiName: 'tauri',
emojiId: '876938722266972210',
roleId: '986176820187631616',
description:
'Join the conversation in the contributors channels (you can still view without this role)',
},
];
? [
{
emojiName: 'sausageroll',
emojiId: '995712110925451324',
roleId: process.env.DEV_REACTION_ROLE,
description:
'Join the conversation in the contributors channels (you can still view without this role)',
},
]
: [
{
emojiName: 'tauri',
emojiId: '876938722266972210',
roleId: '986176820187631616',
description:
'Join the conversation in the contributors channels (you can still view without this role)',
},
];

export const REACTION_ROLE_CHANNEL = DEV_MODE
? process.env.DEV_REACTION_ROLE_CHANNEL
: '616210923354456064';
? process.env.DEV_REACTION_ROLE_CHANNEL
: '616210923354456064';

export const SUPPORT_FORUM = DEV_MODE
? process.env.DEV_SUPPORT_FORUM_CHANNEL
: '1047150269156294677';
? process.env.DEV_SUPPORT_FORUM_CHANNEL
: '1047150269156294677';
export const SOLVABLE_FORUMS = [SUPPORT_FORUM];
export const UNSOLVED_TAG = 'unsolved';
export const SOLVED_TAG = 'solved';
2 changes: 1 addition & 1 deletion src/events/messageCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { add_thread_prefix } from '../utils/threads';

export default event({
name: 'messageCreate',
run: async ({ }, message) => {
run: async ({}, message) => {
// Rules for whether or not the message should be dealt with by the bot
const should_ignore =
message.author.bot ||
Expand Down
Loading