Add roles to users in specific guild through DM - discord.js

When I try
message.member.roles.add('695699359634817094');
I get the following error:
TypeError: Cannot read property 'add' of undefined
Is there a specific way to add my guild ID and update their role to that specific server through DM?
My function works within the guild by calling the command, however, through DM it doesn't.

You could do this by using message.author.id to get the user's ID and then using guild.get(guild_ID).members.fetch(user_ID) to access the GuildMember of that user.
You also mentioned that you give users the ability to run that command either in DM or a text channel in your guild.
If that is the case I would suggest adding a check to see if the command is being sent to a text channel or dm channel.
if (message.channel.type === "dm") {
const member = await client.guilds.get(guild_ID).members.fetch(message.author.id);
member.roles.add(role_ID);
} else {
message.member.roles.add('695699359634817094');
}
Ignore the if statement if you intend on having the command only run from dm.

By using the info given from Syntle and tipakA this is the solution.
if (message.channel.type === "dm") {
client.guilds.get('[SeverId]').members.fetch(message.author.id).then(async () => {
await client.guilds.get('[ServerId]').members.fetch(message.author.id).then((memberid) => {
memberid.roles.add('[roleid]');
}).catch((err) => {
console.log("ERROR");
});
});
}
else
{
message.member.roles.add('[roleid]');
}

Related

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 ignore same command after joining a Voice channel for bot discord.js

How to make a bot to ignore the same command after the bot joins a voice channel?
So if a user with permissions uses a command more than one time, the bot will just ignore the same commands because it has already joined the voice channel (the bot will ignore ?zipfm, but will not ignore others like ?disconnect or ?leave)
I tried making a cool down command, but still, if a user sends ?zipfm command more than one time bot starts to search dispatcher again after every command so we need to ignore that command after first time use.
client.on('message', async(message, user) =>{
if (message.content === '?zipfm'){
const role = message.guild.roles.cache.find((r) => r.name === 'ZIP FM 🎧🎶')
//--------------------------------------------------------------------------------------------------------
if (!role) return message.channel.send(`ZIP FM rolė nėra sukurta. Rašyk \`?sukurti\` norint sukurti ZIP FM rolę!`).then(msg => {
msg.delete({timeout:5000})
})
if (!message.member.roles.cache.has(role.id)) return message.channel.send(`Å i komanda yra leistina tik vartotojams turintiems ${role} rolÄ™.`).then(msg => {
msg.delete({timeout:5000})
})
if (message.channel.type == "dm") return;
if (message.member.voice.channel){
message.member.voice.channel.join().then(connection => {
connection.voice.setSelfDeaf(true);
message.channel.send("Paleidžiama ZIP FM 🎶").then(msg => {
msg.delete({timeout:10000})
})
const dispatcher = connection.play('https://transliacija.zipfm.lt/zipfm128.mp3',{filter: "audioonly"})
})
}
}
After checking if the message content is equal to ?zipfm, you can simply use the GuildMember#voice() function in order to determine whether or not the client is currently inside of a voice channel.
You can simply do that using:
if (message.guild.me.voice) return message.channel.send('I'm already inside of a voice channel!');

Discord.js How can I edit previous bot's message?

so I am trying to make a ROSTER command. The command is $roster add/remove #user RANK. This command basically should edit a previous bot's message (roster) and add a user to the roster to the RANK in the command... This is my code so far, but I haven't managed to make the roster message and the editing part of it and the RANK system. If someone could help that would be very amazing!
//ROOSTER COMMAND
client.on('message', async message => {
if (message.content.startsWith(prefix + "roster")) {
if (!message.member.hasPermission('ADMINISTRATOR')) return message.channel.send('You do not have that permission! :x:').then(message.react(':x:'))
const args = message.content.slice(prefix.length + 7).split(/ +/)
let uReply = args[0];
const user = message.mentions.members.first()
if(!uReply) message.channel.send("Please use `add` or `remove`.")
if(uReply === 'add') {
if(!user) return message.channel.send("Please make sure to provide which user you would like to add...")
message.channel.send(`you are adding **${user.displayName}** from the roster.`)
} else if(uReply === 'remove') {
if(!user) return message.channel.send("Please make sure to provide which user you would like to add...")
message.channel.send(`you are removing **${user.displayName}** from the roster.`)
}
}})
Sounds like the .edit() method is what you want.
Example from the docs:
// Update the content of a message
message.edit('This is my new content!')
.then(msg => console.log(`Updated the content of a message to ${msg.content}`))
.catch(console.error);
To edit your bots previous message, you need to have a reference of the message you want to edit. The returned reference is a promise so do not forget to use await keyword. you can then use .edit() function on the reference to update you msg.
const msgRef = await msg.channel.send("Hello");
msgRef.edit("Bye");

How to add roles when user reacts to specific message

I need it so that a bot will send a message and if anyone on the server reacts to that message with a reaction it will give them a role.
I Have already tried multiple times, different code samples which allow reactions anywhere in the guild but i want it specific to one channel.
client.on("messageReactionAdd", (reaction, user) => {
if (user.bot) return;
const member = reaction.message.member
switch (reaction.name) {
case "😎":
member.addRole("597011179545690121").then((res) => {
reaction.message.channel.send(`You've been given the \`${res.name}\` role!`)
}).catch(console.error);
break;
case "🕵":
member.addRole("597011179545690121").then((res) => {
reaction.message.channel.send(`You've been given the \`${res.name}\` role!`)
}).catch(console.error);
};
})
client.on("messageReactionRemove", (reaction, user) => {
if (user.bot) return;
const member = reaction.message.member
switch (reaction.name) {
case "emoji_name_1":
member.removeRole("roleID").then((res) =>
reaction.message.channel.send(`You've been removed from the \`${res.name}\` role!`)
}).catch(console.error);
break;
case "emoji_name_2":
member.removeRole("someOtherRole").then((res) => {
reaction.message.channel.send(`You've been removed from the \`${res.name}\` role!`)
}).catch(console.error);
};
})
I Want the outcome to be that the person reacts with say a smiley face and they get a certain role but they have to react to a certain message sent by the bot in its own dedicated channel same as pre-made bots such as Reaction Roles bot.
First we have to fetch our Message.
let channel_id = "ChanelID of message";
let message_id = "ID of message";
client.on("ready", (reaction, user) => {
client.channels.get(channel_id).fetchMessage(message_id).then(m => {
console.log("Cached reaction message.");
}).catch(e => {
console.error("Error loading message.");
console.error(e);
});
Then we'll check if someone reacted to our message and give them the appropriate Role
client.on("messageReactionAdd", (reaction, user) => {
if(reaction.emoji.id == "EMOJI ID HERE" && reaction.message.id === message_id)
{
guild.fetchMember(user) // fetch the user that reacted
.then((member) =>
{
let role = (member.guild.roles.find(role => role.name === "YOUR ROLE NAME HERE"));
member.addRole(role)
.then(() =>
{
console.log(`Added the role to ${member.displayName}`);
}
);
});
}
}
I advise against using this code for multiple Roles at once as that would be rather inefficient.
const member = reaction.message.member
Problem: This is defining member as the GuildMember that sent the message, not the one that added the reaction.
Solution: Use the Guild.member() method, for example...
const member = reaction.message.guild.member(user);
switch (reaction.name) {...}
Problem: name is a not a valid property of a MessageReaction.
Solution: What you're looking for is ReactionEmoji.name, accessed via reaction.emoji.name.
...[the users] have to react to a certain message...
Problem: Your current code isn't checking anything about the message that's been reacted to. Therefore, it's triggered for any reaction.
Solution: Check the message ID to make sure it's the exact one you want. If you'd like to allow reactions on any message within a certain channel, check the message's channel ID.
Consider these examples:
if (reaction.message.id !== "insert message ID here") return;
if (reaction.message.channel.id !== "insert channel ID here") return;
Problem: The messageReactionAdd event is not emitted for reactions on uncached messages.
Solution: Use the raw event to fetch the required information and emit the event yourself, as shown here. Alternatively, use Caltrop's solution and fetch the message when the client is ready via TextChannel.fetchMessage().

Add a role to people that react with a certain emoji in a certain channel

I'm trying to make a discord.js bot for my server I made for people in my school. I'm trying to make a #classes channel and if you react to certain messages it gives you a role (which gives you access to the text channel for that class).
client.on('messageReactionAdd', (reaction, user) => {
console.log("client.on completed.")
if (message.channel.name === 'classes') {
console.log("if(message) completed.")
if (reaction.emoji.name === "reminder_ribbon") {
console.log("emoji test completed.")
const guildMember = reaction.message.guild.members.get(user.id);
const role = reaction.message.guild.roles.find(role => role.name === "FACS");
guildMember.addRole(role);
}
}
});
This is what I have tried so far, however, it does not give me/the other people reacted to it the role nor does it return an error message.
P.S. Also, how would I be able to make it so when they unreact it removes the role?
Edit: It seems it only gets reactions from cached messages/messages sent after bot startup. Also, message is not defined on the first if(message.channel.id) message.
Try to use the following code:
client.on('messageReactionAdd', (reaction, user) => {
if (reaction.message.channel.id === '552708152232116224') {
if (reaction.emoji.name === "reminder_ribbon") {
const guildMember = reaction.message.guild.members.get(user.id);
const role = reaction.message.guild.roles.get('552709290427940875');
guildMember.addRole(role);
}
}
});
First of all, reaction.users is an Object with all the users that reacted on the message, so you first have to define to which user you want to assign the role. I fixed this fetching the guildMember with user.id.
The second mistake was that you tried to assign a role ID to a guildMember although you first have to fetch the role and then assign the role Object to the guildMember.

Resources