Problem with webhooks and the role/permissions idea - discord

I develop a bot with discord.js that uses things like msg.member.hasPermission("ADMINISTRATOR") or msg.member.roles.cache.has(teacherRoleID). Everything worked fine until I tried webhooks. By adding these two lines :
client.on('ready', () => {
client.user.setStatus("online")
client.user.setActivity("!help", {
type: "PLAYING",
});
superConsole(`Logged in as ${client.user.tag} in ${client.guilds.size} guilds!`);
const hook = new Discord.WebhookClient("ID", "secret token"); // THESE
hook.send("I am now alive!"); // LINES
});
(btw superConsole is a function)
Since then, the program did not work any more and always returned the same errors: (node:20736) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'hasPermission' of null & (node:20736) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'roles' of null
When I delete these 2 lines for the webhook, it works again. Why? I don't understand.
The permission and role things are in a message listener:
client.on('message', async msg => {
if (msg.member.hasPermission('ADMINISTRATOR') {
// some stuff here
}
if (msg.member.roles.cache.has(teacherRoleID) {
// some stuff here
}
});

The issue is that when you send a message from hook, it triggers the client's message event. Because a webhook isn't a guild member, msg.member will get undefined for messages sent from a webhook.
You would have to use something like this:
if (msg.member) {
if (msg.member.permissions.has('ADMINISTRATOR') {
// some stuff here
}
if (msg.member.roles.cache.has(teacherRoleID) {
// some stuff here
}
}

Related

TypeError: Cannot read properties of null (reading 'permissions') discord.js V13

I try to do a anti link bot discord that only who have the VIEW_AUDIT_LOG permission can send link this is my code :
client.on("messageCreate", message => {
const { member } = message;
let blacklisted = ['http://', 'www.', 'https://'];
let foundInText = false;
if(!member.permissions.has(Permissions.FLAGS.VIEW_AUDIT_LOG)) {
for (var i in blacklisted) {
if (message.content.toLowerCase().includes(blacklisted[i].toLowerCase())) foundInText = true;
}
if (foundInText) {
const logembed = new MessageEmbed()
.setColor("DARK_AQUA")
.addField(' with message :', ` ${message.content} `, true)
if(!message.member.roles.cache.has("929434049011941386")) {
message.guild.channels.cache.get('941704496185221221').send({ content: `<#${message.author.id}> tried to send links in <#${message.channel.id}>`, embeds: [logembed] });;
message.delete();
message.channel.send("No links here, " + `${message.author}`);
}
}
}
});
but it give this error when he delete a message with link :
if(!member.permissions.has(Permissions.FLAGS.VIEW_AUDIT_LOG)) {
^
TypeError: Cannot read properties of null (reading 'permissions')
ok so here's my guess....you're hitting this event handler twice or more times...the first time is the message the user typed. you will get their member info, if you console.log(message.member). The second time through, you'll be getting another event, which is the message(s) you send as a handler.
So the easy solution is to add something like this at or near the top of this event handler:
if (message.author.bot) return;
this basically tests to see if it's a bot or not that's calling your event. It's also good hygiene to ensure you're not accepting/reacting to other bots, which could result in spam you likely don't want.

TypeError: Cannot read property 'ban' of null | Discord.js

Purpose: To ban unauthorised users who kick members out of my server.
Code:
client.on("guildMemberRemove", async member => {
const FetchingLogs = await member.guild.fetchAuditLogs({
limit: 1,
type: "MEMBER_KICK",
});
const kickLog = FetchingLogs.entries.first();
if (!kickLog) {
return console.log(red(`${member.user.tag} was kicked in ${member.guild.name} but nothing was registered in the audit log...`));
}
const { executor, target, createdAt } = kickLog
if (target.id === member.id) {
console.log(greenBright(`${member.user.tag} got kicked in ${member.guild.name}, by ${executor.tag}`));
} else if (target.id === executor.id) {
return
}
if (executor.id !== client.user.id) {
member.guild.member(executor).ban({
reason: `Unauthorised Kick`
}).then(member.guild.owner.send(`**Unauthorised Kick By:** ${executor.tag} \n**Victim:** ${target.tag} \n**Time:** ${createdAt.toDateString()} \n**Sentence:** Ban.`)).catch();
}
})
Result: It bans the executor but it still throws this error:
(node:10272) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'ban' of null
Could you please tell me why this is happening and what I could to remove this error. All help appreciated ;)
This is the offending line:
member.guild.member(executor).ban(....
You supply member.guild.member an executor object and it returns null, then it tries to call the function ban on a null object and you get the error.
Maybe try sending it the executor.id instead, like so:
member.guild.member(executor.id).ban
If you want to ban somebody from a guild you can do this by writing:
member.guild.members.ban(executor.id, { reason: "/* Your reason */" })...
Sources:
https://discord.js.org/#/docs/main/stable/class/GuildMemberManager?scrollTo=ban
and my experience with discord.js

TypeError: Cannot read property 'id' of undefined | Discord.js

Aim: To ban every time a user is caught on the audit log attempting to create a channel
Code:
// Channel Create
client.on("channelCreate", async (channel) => {
const FetchingLogs = await client.guilds.cache.get(channel.guild.id).fetchAuditLogs({
limit: 1,
type: "CHANNEL_CREATE",
})
const ChannelLog = FetchingLogs.entries.first();
if (!ChannelLog) {
return console.log(red(`CHANNEL: ${channel.id} was created.`));
}
const { executor, target, createdAt } = ChannelLog;
if (target.id === channel.id) {
console.log(greenBright(`${channel.id} got created, by ${executor.tag}`));
} else if (target.id === executor.id) {
return
}
if (executor.id !== client.user.id) {
channel.guild.member(executor.id).ban({
reason: `Unauthorised Channel Created`
}).then(channel.guild.owner.send(`**Unauthorised Channel Created By:** ${executor.tag} \n**Channel ID:** ${channel.id} \n**Time:** ${createdAt.toDateString()} \n**Sentence:** Ban.`)).catch();
}
});
Result:
It bans the user successfully but still throws an error.
Error:
TypeError: Cannot read property 'id' of undefined
Code: Error Specified | Referring to channel.guild.id
const FetchingLogs = await client.guilds.cache.get(channel.guild.id).fetchAuditLogs({
limit: 1,
type: "CHANNEL_CREATE",
})
I'm guessing the reason for this is that the parameter ,channel, type is DMChannel and not GuildChannel
Is there any way to fix this or be able to change the parameter type to GuildChannel??? I've checked the Docs and I can't seem to find anything that indicates this is possible. Any help is appreciated ;)
Your assumption of why this error is occurring is correct. The channelCreate event does indeed handle the creation of both GuildChannel and DMChannel, and your code sends the guild owner a DM after banning the user. That's why the ban works but you get an error afterwards; because the DM creates a DMChannel with the owner, triggering the event handler again but with channel.guild being undefined since DMs do not have guilds.
So let me state the problem again. You are getting the error Cannot read property 'id' of undefined which you've figured out means channel.guild is undefined. You don't want the error to occur, so you don't want channel.guild to be undefined. But in your question you're asking:
Is there any way to fix this or be able to change the parameter type to GuildChannel???
That's not the approach you want to take. Doing that would mean users would get banned for DMing your bot because it would trigger your channelCreate event handler; plus, the bot would try to ban the guild owner since it sends the owner a DM. And you only want to ban users for creating channels in the guild.
When we put the problem that way, the solution is simple: check if the channel is a DMChannel, and discontinue if it is. Only allow users to get banned for creating a GuildChannel. So how do you do that? Well, as you've seen from your error already, channel.guild is undefined when the channel is a DMChannel. So simply check for this condition, and return if it is the case. Here's an example:
// Channel Create
client.on("channelCreate", async (channel) => {
if (!channel.guild) return; //<- added this
const FetchingLogs = await client.guilds.cache.get(channel.guild.id).fetchAuditLogs({
limit: 1,
type: "CHANNEL_CREATE",
})
const ChannelLog = FetchingLogs.entries.first();
if (!ChannelLog) {
return console.log(red(`CHANNEL: ${channel.id} was created.`));
}
const { executor, target, createdAt } = ChannelLog;
if (target.id === channel.id) {
console.log(greenBright(`${channel.id} got created, by ${executor.tag}`));
} else if (target.id === executor.id) {
return
}
if (executor.id !== client.user.id) {
channel.guild.member(executor.id).ban({
reason: `Unauthorised Channel Created`
}).then(channel.guild.owner.send(`**Unauthorised Channel Created By:** ${executor.tag} \n**Channel ID:** ${channel.id} \n**Time:** ${createdAt.toDateString()} \n**Sentence:** Ban.`)).catch();
}
});
This prevents the error from occurring, prevents users from getting banned for DMing the bot, and prevents the guild owner from being infinitely DM'd (if the DMChannel were to be somehow converted into a GuildChannel, the bot would DM the owner after banning the user that created the channel, which would trigger the event again and ban the user again, and DM the owner again, in an infinite loop).

How to use the awaitMessages function in discord.js

I have some code for discord.js that sends a user a DM when they join the server. They then have to enter the password given to them, and it will then give them a role that allows them access to channels.
const Discord = require('discord.js');
const client = new Discord.Client();
client.once('ready', () => {
console.log('Ready!');
});
client.on('guildMemberAdd', guildMember => {
console.log("Joined");
guildMember.send("Welcome to the server! Please enter the password given to you to gain access to the server:")
.then(function(){
guildMember.awaitMessages(response => message.content, {
max: 1,
time: 300000000,
errors: ['time'],
})
.then((collected) => {
if(response.content === "Pass"){
guildMember.send("Correct password! You now have access to the server.");
}
else{
guildMember.send("Incorrect password! Please try again.");
}
})
.catch(function(){
guildMember.send('You didnt input the password in time.');
});
});
});
client.login("token");
The thing is, I don't really know how to use the awaitResponses function. I do not know how to call it, because all the tutorials I find use it with message.member.
When I run my code, I get these three errors:
UnhandledPromiseRejectionWarning: TypeError: guildMember.awaitMessages is not a function
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.
I do not know what lines these are referring to, so I am very confused.
Here's a quick rundown on how awaitMessages works:
First of all, the .awaitMessages() function extends GuildChannel, meaning you had already messed up a little bit by extending the GuildMember object instead. - You could easily fetch a channel using
const channelObject = guildMember.guild.channels.cache.get('Channel ID Here'); // Gets a channel object based on it's ID
const channelObject = guildMember.guild.channels.cache.find(ch => ch.name === 'channel name here') // Gets a channel object based on it's name
awaitMessages() also gives you the ability to add a filter for a certain condition an input must have.
Let's take the freshly new member as an example. We could simply tell the client to only accept input from members who have the same id as the guildMember object, so basically only the new Member.
const filter = m => m.author.id === guildMember.id
Now, finally, after we've gathered all of the resources needed, this should be our final code to await Messages.
const channelObject = guildMember.guild.channels.cache.get('Channel ID Here');
const filter = m => m.author.id === guildMember.id
channelObject.awaitMessages(filter, {
max: 1, // Requires only one message input
time: 300000000, // Maximum amount of time the bot will await messages for
errors: 'time' // would give us the error incase time runs out.
})
To read more about awaitMessages(), click here!

Getting every channel in a guild

I'm trying to get every channel in a discord guild, but it gives me an error message.
if (message.content.startsWith('!get-channels')) {
message.guild.channels.forEach(channel => {
console.log(channel)
})
}
Here is the error message:
message.guild.channels.forEach(channel => {
^
TypeError: message.guild.channels.forEach is not a function
You are getting that error because since discord.js v12 you now need to access Guild Channels using their cache, so your solution would be to use message.guild.channels.cache.forEach()

Resources