I keep getting thrown "client.guilds.get(...).member(...).roles.add is not a function" and I've tried numerous threads on changing lines, but none really solved the issue that I had.
I've tried to change message.author to message.member, but it didn't seem to work and gave me plentyful more errors.
client.on('message', (message) => {
if (message.author.bot || !message.author.token || message.channel.type !== `dm`) return
if (message.content !== (verifymsg.replace('{token}', message.author.token))) return
message.channel.send({
embed: {
color: Math.floor(Math.random() * (0xFFFFFF + 1)),
description: completemsg,
timestamp: new Date(),
footer: {
text: `Verification Success`
}
}
})
client.guilds.get(config.guild).member(message.author).roles.add(config.role) // ensure this is a string in the config ("")
.then(console.log(`TOKEN: ${message.author.token} :: Role ${config.role} added to member ${message.author.id}`))
.catch(console.error)
})
The user is supposed to get a role "Member" after verifying with the line given to them to say.
Just as the error says, GuildMember.roles.add() is not a function. GuildMember.roles returns a Collection, and add() is not a method of a Collection or a Map (Collection extends Map).
You should use GuildMember.addRole().
client.guilds.get(config.guild).member(message.author).addRole(config.role)
Related
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).
I'm trying do create a bot that can add specific role to the user who react to the message with the emoji listed.
With the code below, I can check who reacted to the message and i can also check what emoji they react with, but when I am trying to add role to them, error pops up say user.addRole is not a function is there any way to solve this problem? Thanks a lot!
Code that create an embed message for user to react
let args = message.content.substring(PREFIX.length).split(" ");
if(message.content.toLowerCase() === '?roles' && message.author.id === 'adminId' && message.channel.id === 'channel id'){
const role = new Discord.MessageEmbed()
.setTitle("ROLES")
.setColor('#6a0dad')
.setDescription('š„ - ROLE1\nāļø - ROLE2\nš§ - ROLE3')
message.channel.send(role).then(re => {re.react('š„'),re.react('āļø'),re.react('š§')});
message.awaitReactions().then(collected=>{
const reaction = collected.first();
})
}
Code that get the react user and trying to add role
const bot = new Discord.Client({ partials: ['MESSAGE', 'CHANNEL', 'REACTION'] });
bot.on('messageReactionAdd', async (reaction, user) => {
if (reaction.partial) {
try {
await reaction.fetch();
} catch (error) {
console.log('Something went wrong when fetching the message: ', error);
return;
}
}
if(reaction.message.id === 'id of that embed message sent'){
if(reaction.emoji.name === "š„"){
//console.log('ROLE1');
user.addRole('id of role 1');
}
if(reaction.emoji.name === 'āļø')
//console.log('ROLE2');
user.addRole('id of role 2');
if(reaction.emoji.name === 'š§')
//console.log('ROLE3');
user.addRole('id of role 3');
}
});
Looks like you're trying to add a role to a User. When you should be adding the role to a GuildMember. As you can see here: messageReactionAdd returns a User. However Users don't have a .roles only GuildMembers do. However you have two ways you can get the GuildMember easily:
This way you have to make sure the message is from a TextChannel not a DMchannel.
if(reaction.message.type === "text") let member = reaction.message.member;
OR
This way allows the user to react to ANY message the bot has cached.
let member = bot.guilds.get('<id of the server>').members.get(user.id);
Then you do what #Syntle said: member.roles.resolve('<id of role>');
The choice of how to get the member is up to you.
user.addRole() needs to be replaced with member.roles.add.
const member = message.mentions.members.first()
if (!message.mentions.users.size) {
return message.channel.send('You have to mention a user to kick him!');
} else if (member === message.author) {
return message.channel.send('You can\'t kick yourself!');
} else if (!member.kickable) {
return message.channel.send('You cannot kick this user!');
} else {
return member
.kick()
.then(() => message.message.send(`${member.user.tag} was kicked.`))
.catch(error => message.message.send(`Sorry, an error occured.`))
}
I'm trying to create a code that kicks a user, but in some situations I don't want the user to be able to kick another user. One of these situations is when the user to be kicked is the same one who writes the command. The problem is that i can't do this piece of code and every time it tells me: 'You cannot kick this user!' when it should say: 'You can't kick myself'. How can i display that message when i try to kick myself?
P.S. Sorry for my english, i'm italian
Replace } else if (member === message.author) { with } else if (member.id === message.author.id) {
That way it checks for the ID instead of the member / message author object, and the ID will definetly be identical.
Your if block is not triggering for two reasons. First of all, MessageMentions.members returns a collection of GuildMembers, while Message.author returns a User object. You can learn about the difference here.
Second of all, even if the two objects were the same type, Objects in JavaScript can fundamentally never be equal.
console.log({} === {}); // false
console.log({ property: true } == { property: true }); // false
console.log({ string: 'something' } === { string: 'something' }); // false
Luckily, you can use the Collection.prototype.equals method, which takes this into account. So if you wanted to, you could use this:
// const member = message.mentions.members.first()
if (member.equals(message.member))
However, there's another method that's easier, which is simply comparing the id property of both objects. The id is the same in both the User and GuildMember objects, and it is completely unique to someone's Discord profile.
// const member = message.mentions.members.first()
if (member.id === message.author.id)
msg.guild.channels.find(c => c.id == "693088078168064051").send(tempVars("absence_review"))
.then(function(message) {
const approved = message.react("ā
")
.then(() => message.react("ā"))
.catch(error => {});
const filter = (reaction, user) => {
return ['ā
', 'ā'].includes(reaction.emoji.name) && user.id === message.author.id;
};
message.awaitReactions(filter, {
max: 1
})
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === 'ā
', reaction.user.bot === false) {
message.reply('reacted with yee.');
} else if (reaction.emoji.name === 'ā', reaction.user.bot === false) {
message.reply('reacted with nah dude.');
}
})
.catch(collected => {
message.reply('you didnt react idiot');
});
That is the code I am currently using for the command. What I am making this command to do is to record an absence, send it to another channel with reactions, have someone react to it and if they react with the checkmark, it will send it back to the channel where the command was originally sent, but if they react to the cross, the person who originally made the command gets DM'd by the bot. Those last few things are easy, but my main issue is the reactions. I have made the reactions appear, but the last bit of the code seems to break it. Everything after the 'const filter' bit. If I remove all that, then it will just send the embed message with the reactions, but the reactions won't do anything. However, if I keep that in. It won't even send the message, I get an error stating "SyntaxError: Unexpected end of input" Now I have googled for this for around an hour, getting friends to help but unfortunately nothing is helping. If anyone could help it would be greatly appreciated, thanks in advance.
Although I cannot see the whole code, I believe your error is thrown not from the code above. The syntax error 'unexpected end of input' is usually caused by not finishing a bracket or brackets i.e )}; in somewhere in your code - commonly after the 'client on' function in your main.js file. Go through your whole code and make sure every bracket is properly represented. Maybe put your code into code.vb - it detects and points out syntax errors like the one you have above.
Let me know of progress.
I have spent yet another 3 hours in my mini dungeon figuring this out and got something to somewhat work.
msg.guild.channels.find(c => c.id == "693088078168064051")
.send(tempVars("absence_review")).then(function(message){
message.react("ā
")
.then(() => message.react("ā"))
.catch(error => {});
});
const filter = (reaction, user) => {
return ['ā
', 'ā'].includes(reaction.emoji.name) && user.id === message.author.id;
};
message.awaitReactions(filter, {
max: 1
})
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === 'ā
', reaction.user.bot === false) {
message.reply('reacted with yee.');
} else if (reaction.emoji.name === 'ā', reaction.user.bot === false) {
message.reply('reacted with nah dude.');
}
})
.catch(collected => {
message.reply('you didnt react idiot');
});
This is a fixed version of it, although the last bit doesn't necessarily work, I will try figure the rest out by myself.
I am trying to make a tempmute command, I followed a tutorial online which worked... But my own server has users with multiple roles, and these roles allow them to talk even when they receive the "muted" role.
Is there any way to save all the roles from a mentioned user and then to remove and add those roles?
I already tried to make a new let variable
let roleHistory = tomute.member.roles;
and then adding and removing them with:
await(tomute.removerole(roleHistory));
tomute.addRole(roleHistory);
But that didn't work
module.exports.run = async (bot, message, args) => {
let tomute = message.guild.member(message.mentions.users.first() || message.guild.members.get(args[0]));
if(!tomute) return message.reply("Couldn't find user.");
if(tomute.hasPermission("MANAGE_MESSAGES")) return message.reply("Can't mute them!");
let muterole = message.guild.roles.find(`name`, "muted");
if(!muterole){
try{
muterole = await message.guild.createRole({
name: "muted",
color: "#000000",
permissions:[]
})
message.guild.channels.forEach(async (channel, id) => {
await channel.overwritePermissions(muterole, {
SEND_MESSAGES: false,
ADD_REACTIONS: false
});
});
}catch(e){
console.log(e.stack);
}
}
let mutetime = args[1];
if(!mutetime) return message.reply("You didn't specify a time!");
await(tomute.addRole(muterole.id));
message.reply(`<#${tomute.id}> has been muted for ${ms(ms(mutetime))}`);
setTimeout(function(){
tomute.removeRole(muterole.id);
message.channel.send(`<#${tomute.id}> has been unmuted!`);
}, ms(mutetime));
}
I want the bot to take the roles away, tempmute the user and giving the roles back after the Timeout.
Your attempt is on the right track, but you missed a small detail. A Guild Member has a method addRole and removeRole which you used. However, these methods are meant for adding/removing a single role.
When you first fetch the user roles with let roleHistory = tomute.member.roles;, it returns a Collection of roles. If you then attempt to use removeRole(roleHistory) it attempts to remove a single role equal to the complete collection (which doesn't exist obviously).
To make it work, you need the methods addRoles and removeRoles which adds/removes an entire collection. So your code would be:
let roleHistory = tomute.roles;
// Removing all the roles
await(tomute.removeRoles(roleHistory));
// Adding all the roles
tomute.addRoles(roleHistory);
P.s. Since your tomute variable is already a user you need to change your code to fetch the roles from let roleHistory = tomute.member.roles; to let roleHistory = tomute.roles;