I am creating a Discord Bot.
I am trying create a Mute command, but I always get the same error.
What went wrong?
Background information:
Discord.js version: 12.0.0-dev
Klasa with version 0.5.0-dev is used
Code:
const { Command } = require('klasa');
const { MessageEmbed } = require('discord.js');
module.exports = class extends Command {
constructor(...args) {
super(...args, { description: 'Mute an user.' })
}
async run(msg, args) {
if(!msg.member.hasPermission("MANAGE_MEMBERS")) return msg.channel.send("You can't use this command.");
let MuteUser = msg.guild.member(msg.mentions.users.first() || msg.guild.members.get(args[0]))
if(!MuteUser) return msg.channel.send("Can't find user!");
let MuteReason = msg.content.split(" ").slice(2).join(" ");
let MuteRole = msg.guild.roles.find(r => r.name === "Spammer");
if(!MuteRole) return msg.channel.send("Can't find the Spammer role!");
let MuteChannel = msg.guild.channels.find(guild => guild.name === 'bot-logs');
if(!MuteChannel) return msg.channel.send("Can't find the #bot-logs channel.");
if(MuteUser.roles.has(MuteRole)) return msg.channel.send("That user is already muted!.");
MuteUser.addRole(MuteRole.id);
return MuteChannel.send(new MessageEmbed()
.setAuthor("Mute"|| 'Unknown', "http://wolfdevelopment.cf/BotSymbols/info.png")
.setColor("#ff0000")
.addField("Muted User", `${MuteUser}`)
.addField("Muted By", `<#${msg.author.id}>`)
.addField("Muted In", `${msg.channel}`)
.addField("Time", `${msg.createdAt}`)
.addField("Reason", `${MuteReason}`));
}
}
I have checked that MuteUser is a person in this line:
if(!MuteUser) return msg.channel.send("Can't find user!");
So it must be a person. Why doesn't it have an addRole function?
I decided to look at this from another viewpoint and searched the Discord.js documentation for some more information. Sure enough, something is found:
I assume your call to msg.guild.member would result in a GuildMember because that is what the name implies.
Stable (Presumably 11.x): https://discord.js.org/#/docs/main/stable/class/GuildMember
Note that addRole is the first item below Methods.
Now, switching to master (aka Development branch - where you got 12.0.0-dev from)...
https://discord.js.org/#/docs/main/master/class/GuildMember
addRole isn't there anymore.
Clicking the type of roles...
https://discord.js.org/#/docs/main/master/class/GuildMemberRoleStore
add is the first method.
You can probably replace MuteUser.addRole with MuteUser.roles.add.
Note: This does not invalidate any of my words in the comments because you didn't provide enough information in the question itself on what type MuteUser is when the error was thrown.
Note 2: This took one Google search only. How much work did you even put into research?
User don't have addRole : https://discord.js.org/#/docs/main/stable/class/User
But GuildMembers does.
Are you trying to cast to a member in the line where you defined "let MuteUser" ? It could be normal that it does not have the addRole methods if it' a user.
First: users don't have a role. Only members have roles.
Users are a discord user = a real life person (or a bot)
A Member object is a user "attached" to a server. So a member can have roles, because you only have roles within a specific server.
I tried someMember.addRole(someRole) too, and got the same addRole is not a function, error message.
Just try someMember.roles.add(someRole) and it works!!!
Providing I have:
guildID: the server ID
userID: the user ID
roleID: the role ID
memberID: NO !!! haha, got you!!! Members don't have IDs on Discord. A member is defined by a guildID and a userID, but it does not have an ID of it's own.
So, if I want to add a role to a member, here is what I do:
// get the guild
const guild = client.guilds.cache.get(guildID);
if (! guild) return console.error("404: guild with ID", guildID, "not found");
// get the member
const member = guild.members.cache.get(userID);
if (! member) return console.error("404: user with ID", userID, "not found in guild", guild.name);
// we check our bot has role management permission
if (! guild.me.hasPermission('MANAGE_ROLES'))
return console.error("I don't have the right to manage roles !!! :-( ");
// get the role
const role = guild.roles.cache.get(roleID);
if (! role) return console.error("404: role with ID", roleID, "not found in guild", guild.name);
// add role to member
member.roles.add(role)
.then(function() {
console.log("role", role.name, "added to", member.user.name, "on server", guild.name);
// do your stuff
})
.catch(function(err) {
console.error("could not assign role", role.name,
"to", member.user.name,
"on server", guild.name,
"because", error.message);
// cry
});
If that does not work:
Check that the highest role of the member is less powerfull than the highest role of your bot
Check that the role your bot is trying to add, is less powerfull than the highest role of your bot
And also: in the role configuration page of your server configuration, in the role list, make sure the role you are trying to attribute, is listed under the role of your bot (you can drag the roles to re-order them). (that one took me hours to figure out !!!)
Related
I'm new at JS and I'm trying to make my bot give a specific role to a specific member.
If you can help me, please, do this.
The code:
bot.on("message", (msg) => {
if ((msg.content === "!give", role, member))
var role = msg.guild.roles.cache.find((r) => {
return r.name === "convidado astolfofo";
});
var member = msg.mentions.members.first();
member.roles.add(role);
console.log(member);
console.log(role);
});
The errors I encountered:
(node:2364) UnhandledPromiseRejectionWarning: TypeError [INVALID_TYPE]: Supplied roles is not a Role, Snowflake or Array or Collection of Roles or Snowflakes.
TypeError: Cannot read property 'add' of undefined discord.js
There are a couple of errors with your code. I'm not sure what you tried to do with if ((msg.content === "!give", role, member)) -- probably checking if the message starts with !give and if there is a role and a member -- but it won't work like that in JavaScript. You need to check them separately and once these variables are defined.
If you check if msg.content === "!give" but you also want the member to mention a member, it will never be true. If the whole message is just !give, there is no mentioned user. If there is a mentioned user, msg.content will be more than !give. Try to check if the message.content starts with "!give".
Next, if you don't use curly braces following your if statement, only the next line is inside that statement. So you try to check if the command is !give, and if it is, you search for a role, but the following lines where you check where you add the role are outside of this statement. It means, it runs on every incoming message. Try to use curly braces.
It's also a good idea to check permissions and send replies to let the user know if there are any missing ones.
Check the working example below, I've added comments to make it easier to understand:
bot.on('message', async (msg) => {
if (msg.content.startsWith('!give')) {
// check if the message author has the permission to add a role
if (!msg.member.hasPermission('MANAGE_ROLES')) {
return msg.reply('You need `MANAGE_ROLES` permission to add a role');
}
// check if the bot has the permission to add a role
if (!msg.guild.me.hasPermission('MANAGE_ROLES')) {
return msg.reply('I do not have `MANAGE_ROLES` permission to add a role');
}
// check if there is a member mentioned
const member = msg.mentions.members.first();
// if there is none, send a reply
if (!member) {
return msg.reply("Don't forget to mention someone!");
}
// search for the role
// don't forget that it's case-sensitive
const role = msg.guild.roles.cache.find((r) => r.name === 'convidado astolfofo');
// check if the role exists
if (!role) {
return msg.reply("Oh-oh, I can't find the role `convidado astolfofo`");
}
// try to add a role
try {
await member.roles.add(role);
msg.reply(`Role added to ${member}`);
} catch (error) {
console.log(error);
msg.reply('Oops, role not added, there was an error');
}
}
});
You seem to be using return incorrectly. Try this:
bot.on("message", (msg) => {
if ((msg.content === "!give", role, member))
var role = msg.guild.roles.cache.find(r => r.id === "<role id goes here>");
var member = msg.mentions.members.first();
member.roles.add(role);
console.log(member.username);
console.log(role.name);
});
I also changed your console.log statements since your console would get spammed with objects
I'm pretty new to discord.js but I'm trying to make a bot give roles based on time elapsed since the user joined (the bot's role is above the needed roles and the bot itself has admin permissions)
client.on("guildMemberAdd", (member) => {
member.roles.add(801917861110874122);
});
client.on("message", (message) => {
if(Date.now() - message.member.joinedAt < 1000*60*60*24*1) {
message.member.roles.add(801917434558808074);
}
});
Basically, the bot doesn't give the role neither when the user joins nor when the wanted amount of time passes.
You need to pass a role to .add(), which can be done by looking up the ID from the cache.
Here is an example:
let role = message.guild.roles.cache.get("801917861110874122");
member.roles.add(role);
You can also search through roles using the name instead of the ID like this:
let role = message.guild.roles.cache.find(r => r.name == "Role name");
member.roles.add(role);
Edit:
To make your time function work, you need to use message.member.joinedTimestamp instead of message.member.joinedAt, like this:
client.on("message", (message) => {
if(Date.now() - message.member.joinedTimestamp < 1000*60*60*24*1) {
message.member.roles.add(801917434558808074);
}
});
So, I'm making a kick command, what happens is, when you don't specify a reason or you dont mention a user to kick, the bot responds back to you correctly, but the bot DOESNT kick the mentioned user.
Here's my code.
const { MessageEmbed } = require('discord.js')
module.exports = {
name: "kick",
description: 'Kicks a user.',
usage: "<user mention> < reason>",
execute(message, args){
let kickedMember = message.mentions.users.first() || "No reason specified."
let reason = args.slice(1).join(" ")
if(!message.member.hasPermission(["KICK_MEMBERS"])) return message.reply("You don't have the
required permissions to run this command.")
if(!kickedMember) return message.channel.send('Please mention a user to kick.')
if(!reason) return message.reply("Please specify a reason.")
kickedMember.send(`You have been kicked in ${message.guild.name} due to ${reason}, read the
rules to avoid being kicked next time`).then(() =>
kickedMember.kick()).catch(err => console.log(err))
const embed = new MessageEmbed()
.setTitle('User Kicked')
.addField("User Kicked", kickedMember)
.addField("Reason", reason)
.addField("Moderator", message.author.tag)
.addField("Kicked Date", message.createdAt.toLocaleString())
.setThumbnail(kickedMember.displayAvatarURL())
.setColor()
.setFooter(`Kicked by ${message.author.tag}`)
.setTimestamp(Date.now())
message.channel.send(embed);
}
}
Yes, I did define MessageEmbed but it wont show up in this code for some reason.
You cannot kick a user, you can only kick a member, and you should also check if the member is kickable using .kickable. Discord.js's GuildMember has a property called GuildMember#kickable which will return true if the user can be kicked, what you want to do is add it to your code:
// Define Discord and use it for the MessageEmbed(), because it may be an error at that part.
const Discord = require('discord.js');
module.exports = {
name: "kick",
description: 'Kicks a user.',
usage: "<user mention> <reason>",
execute(message, args){
// Get the `member` property not the `user` property.
let kickedMember = message.mentions.members.first()
// I think you meant to put the "No Reason Specified." here?
let reason = args.slice(1).join(" ") || "No Reason Specified"
// `.hasPermission()` is deprecated
if(!message.member.permissions.has(["KICK_MEMBERS"])) return message.reply("You don't have the required permissions to run this command.")
if(!kickedMember) return message.channel.send('Please mention a member to kick.')
// You don't need this, since you added "No Reason Specified above."
// if(!reason) return message.reply("Please specify a reason.")
// Avoid using whatever you did here, because it might break.
// kickedMember.send(`You have been kicked in ${message.guild.name} due to ${reason}, read the rules to avoid being kicked next time`).then(() =>
// kickedMember.kick()).catch(err => console.log(err))
// Check if the bot has permission
const botMember = message.guild.members.cache.get(client.user.id);
if (!botMember.permissions.has(['KICK_MEMBERS'])) return message.reply('The bot doesn't have the required permission /`KICK_MEMBERS/`');
// Check if the member is kickable
if (!kickedMember.kickable) return message.reply('This member cannot be kicked, check if they have a higher role than the bot!')
// Kick the member and then send the message, not the other way around.
kickedMember.kick({
reason: reason
}).then(member => { // This passes `member` as the member that was kicked.
// Send the message to the kicked member
member.send(`You have been kicked in ${message.guild.name} due to ${reason}, read the rules to avoid being kicked next time`).catch(err => console.log(err));
const embed = new MessageEmbed()
.setTitle('User Kicked')
.addField("User Kicked", member.tag) // Don't pass their data, just tag, because
// once you kick them, they're no longer
// in the cache.
.addField("Reason", reason)
.addField("Moderator", message.author.tag)
.addField("Kicked Date", message.createdAt) // `.createdAt` is already a string.
.setThumbnail(member.displayAvatarURL())
.setColor()
.setFooter(`Kicked by ${message.author.tag}`)
.setTimestamp() // You don't need `Date.now()` discord automatically parses
// the timestamp into string.
// Send the embed
message.channel.send(embed);
})
}
}
For more info, check out these links:
Discordjs.guide - Guide - Kicking a member
Discordjs.guide - Guide - Permissions
Discord.js - Docs - GuildMember property
Discord.js - Docs - GuildMember#kickable property
I've been working on a discord bot in discord.js that assigns a role to the people mentioned in this framework:
${prefix}assignrole ${role} ${user1} ${user2} ${user3} ...
I have figured out a way to assign the role to one person but I can't find a way to assign it to many people. Heres my code:
if(command === "assignrole"){
if(!message.member.roles.some(r=>["Defenestration Administration", "Moderator", "Admin", "Administrator/Creator"].includes(r.name)) )
return message.reply("Sorry, you don't have permissions to use this!");
var role = message.mentions.roles.first();
var roleId = message.mentions.roles.first().id
message.mentions.members.first().addRole(roleId)
if(!role) {
return message.channel.send("Wrong Input, Must Type a Valid Role After the Command!")
}
}
Can someone help me by showing me a way to assign multiple users a role.
Any answers or help are appreciated, thanks :)
-Joshua
message.mentions.members is a collection. It contains all the members you mentioned in the message. You can loop through the aforementioned collection and add the role.
if (command === "assignrole") {
const Role = message.mentions.roles.first();
message.mentions.members.forEach(member => {
member.roles.add(Role).catch(e => console.error(e));
});
message.channel.send(`Added role ${Role.name} to ${message.mentions.members.map(member => member.user.tag).join(", ")}.`);
}
In addition to #Jakye, you can also use a for loop to avoid rate limit with an async system.
client.on("message", async message => {
let membersArray = message.mentions.members.array();
for(var guildMemberId in membersArray) {
await membersArray[guildMemberId].roles.add(message.mentions.roles.first());
}
message.channel.send("All members have received the role " + message.mentions.roles.first().name + ".");
}
bot.on('messageReactionAdd', async (reaction, user) => {
// Define the emoji user add
let role = message.guild.roles.find(role => role.name === 'Alerts');
if (message.channel.name !== 'alerts') return message.reply(':x: You must go to the channel #alerts');
message.member.addRole(role);
});
Thats the part of my bot.js. I want the user to react in a certain channel and receive role Alerts
You haven't really stated what the problem is, what works and what doesn't work but I'll take a wild stab at some parts which catch my eye.
For starters you are calling properties on the variable message whilst in the code you supplied, you didn't create/set a variable named message. My guess is that you want the message to which a reaction has been added. To do that you have to use the MessageReaction parameter which is supplied in the messageReactionAdd event as reaction.
From there you can replace message.<something> with reaction.message.<something> everywhere in the code you supplied.
Something also to note is that you add the role Alerts to message.member. This won't work how you want it to, since it will give the Alerts role to the author of the original message.
What (I think) you want to do, is fetch the user who just reacted with the emoji and assign them the Alerts role. You'll have to find the member in the guild first and then assign them the Alerts role. To do this you'll have to use the User parameter and find the correct Member because you can't add a role to a User object but you can to a Member object. Below is some code which should hopefully put you on the right track.
// Fetch and store the guild (the server) in which the message was send.
const guild = reaction.message.guild;
const memberWhoReacted = guild.members.find(member => member.id === user.id);
memberWhoReacted.addRole(role);
You are using message.member variable despite not defining message.
Any of these methods won't really work in v12 so I updated it for someone else searching.
If you find any mistakes be sure to make me aware of it.
const Discord = require('discord.js');
const client = new Discord.Client({ partials: ['MESSAGE', 'CHANNEL', 'REACTION'] }); //partials arent really needed but I woudld reccomend using them because not every reaction is stored in the cache (it's new in v12)
const prefix = "-";
client.on('messageReactionAdd', async (reaction, user) => {
if (reaction.partial) { //this whole section just checks if the reaction is partial
try {
await reaction.fetch(); //fetches reaction because not every reaction is stored in the cache
} catch (error) {
console.error('Fetching message failed: ', error);
return;
}
}
if (!user.bot) {
if (reaction.emoji.id == yourEmojID) { //if the user reacted with the right emoji
const role = reaction.message.guild.roles.cache.find(r => r.id === yourRoleID); //finds role you want to assign (you could also user .name instead of .id)
const { guild } = reaction.message //store the guild of the reaction in variable
const member = guild.members.cache.find(member => member.id === user.id); //find the member who reacted (because user and member are seperate things)
member.roles.add(role); //assign selected role to member
}
}
})
Here's a quick answer, though way too late. So I'll be updating the answer with Discord.js v.12.x (or the same as Discord.js Master)
bot.on('messageReactionAdd', async (reaction, user) => {
//Filter the reaction
if (reaction.id === '<The ID of the Reaction>') {
// Define the emoji user add
let role = message.guild.roles.cache.find((role) => role.name === 'Alerts');
if (message.channel.name !== 'alerts') {
message.reply(':x: You must go to the channel #alerts');
} else {
message.member.addRole(role.id);
}
}
});