Another day another project. Today I am using Node.js to create a Discord bot to automatically remove members from a Discord thread or post who lost the “view channel” permission to said category or parent channel.
Normally you would see a strike-through in the list of participants in the channel, then rightclick on the member and choose “Remove x from thread”. Now the bot has to do this from ALL existing threads.
import { Client, GatewayIntentBits, Partials } from 'discord.js';
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildScheduledEvents
],
partials: [Partials.Message, Partials.Channel, Partials.Reaction],
});
const TOKEN = '**HIDDEN**';
client.once('ready', async () => {
console.log(`Logged in as ${client.user.tag}!`);
// Check access for all existing threads
try {
await checkAllThreads();
} catch (error) {
console.error('Error checking all threads:', error);
}
});
async function checkMemberAccess(thread) {
try {
const members = await thread.members.fetch();
const channel = thread.parent;
members.forEach(async member => {
const guildMember = await thread.guild.members.fetch(member.id);
const hasAccessRole = guildMember.roles.cache.some(role => {
return channel.permissionsFor(role).has('VIEW_CHANNEL');
});
if (!hasAccessRole) {
await thread.members.remove(member.id);
console.log(`Removed ${member.user.tag} from thread ${thread.name}`);
}
});
} catch (error) {
console.error('Error checking thread members:', error);
}
}
async function checkAllThreads() {
client.guilds.cache.forEach(async guild => {
try {
const threads = await guild.threads.fetch();
threads.forEach(async thread => {
await checkMemberAccess(thread);
});
} catch (error) {
console.error(`Error checking threads for guild ${guild.name}:`, error);
}
});
}
client.on('threadCreate', thread => {
// Check access when a new thread is created
checkMemberAccess(thread);
});
client.login(TOKEN);
For obvious reasons I hid the token, the bot successfully connects and comes online. The problem I am having is that it is throwing an error code:
Logged in as thread#8061!
Error checking threads for guild T1MAT0's server: TypeError: Cannot read properties of undefined (reading 'fetch')
at file:///home/runner/threadbot/index.js:49:43
at _Collection.forEach (<anonymous>)
at checkAllThreads (file:///home/runner/threadbot/index.js:47:23)
at Client.<anonymous> (file:///home/runner/threadbot/index.js:19:11)
at Object.onceWrapper (node:events:633:26)
at Client.emit (node:events:518:28)
at WebSocketManager.triggerClientReady (/home/runner/threadbot/node_modules/discord.js/src/client/websocket/WebSocketManager.js:388:17)
at WebSocketManager.checkShardsReady (/home/runner/threadbot/node_modules/discord.js/src/client/websocket/WebSocketManager.js:371:10)
at WebSocketShard.<anonymous> (/home/runner/threadbot/node_modules/discord.js/src/client/websocket/WebSocketManager.js:201:16)
at WebSocketShard.emit (node:events:518:28)
Does anyone have a suggestion on how to resolve this issue?