Finding all members with a role in Discord.js - node.js

I have tried literally using what everyone says and it just keeps giving me empty arrays or undefined. I am using discord.js v12 I believe.
I am REALLY certain that I actually have members with this role and that the roleID is correct. Why is this wrong? compare new_channel to channel. I suppose the ${} in the find function is not necessary but that is not the issue. Up to the roles.cache.get(importantRole.id) part it goes right, but I can't seem to get the members from it.
let importantRole = await new_channel.guild.roles.cache.find(r => r.name === `${new_channel.name}`)
console.log(importantRole.id) // --> gives the right role ID
let membersWithRole = await new_channel.guild.roles.cache.get(importantRole.id).members.map(m=>m.user.id);
console.log(membersWithRole) // --> gives []

Most likely the members with that role are not cached. You need to:
Enable the GUILD_MEMBERS privileged intent on the Discord developer panel if you have not already (if your bot is less than 100 guilds this is a simple toggle; if your bot has >100 guilds and is verified you need to apply for these, it's to protect user privacy), and
Enable the GUILD_MEMBERS privileged intent in your Discord.js Client's options (the object that is passed to new Client({...}) by passing { ws: { intents: [ 'GUILD_MEMBERS' ] } }
Fetch all of the guild's members when this command/module/etc runs (only do this when strictly necessary, and not on an interval, as it causes an extra API call)
Also, there's no need to do `${variable}` as variable does the same thing. The ` and ${...} syntax are only needed when merging variables with strings `like${this}` (= 'like' + this)
To fetch all guild members, you can do:
<Guild>.members.fetch() // => Promise<GuildMemberManager>
Note that for some reason, in my testing, the value of the resolved promise doesn't work as a valid GuildMemberManager, so you should do:
// _ = temporary var
<Guild>.members.fetch().then((_) => {
// do something with <Guild>.members.cache
});

Related

Lost ability to capture unique Conversation_ID for each new session

Using Bot Builder 4.11.1 .Net and seemed to have lost the ability to capture any unique identifier for each new session. I need a unique identifier to keep state with the AI engine I am using to respond to input. Any suggestions? So, to expand, if I have a slack bot, for example, each time a user logs into Slack and starts a conversation with MyBot, I need a new unique identifier.
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var welcomeText = "Hello and welcome!";
Random rnd1 = new Random();
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText, welcomeText), cancellationToken);
}
}
}
}
Unless I'm missing something, you should be able to get the information you need from TurnContext. In my code I'm running this in onMessage only (as in my case I only will message the user if they have sent the bot a message), but I don't see why you couldn't use this in onMembersAdded as well. I don't know how channels like Slack work, but in Microsoft Teams the user is just "added" when they first talk to the bot, and you don't end up in onMembersAdded unless they remove and read the bot in Teams. So if you may want to grab the conversation reference in the future, you may want to have it in onMessage or in both places. Also if you need the activity ID for some reason, as this will obviously update with each activity (though I haven't had any need for this information). Here is how you get the conversation reference. I am storing this in my conversation state and have assumed you are familiar with that but let me know if you need further help there. I also store in an Azure table to be accessed outside of the bot (e.g. I have an Azure Function that uses this to send proactive followups).
const { TurnContext } = require('botbuilder');
const conversationData = await this.dialogState.get(context, {});
conversationData.conversationReference = TurnContext.getConversationReference(context.activity);
await this.conversationState.saveChanges(context);
And that's it! Here is a sample conversation reference. Note that if you are storing this in Azure Tables or similar, you'll likely need to stringify it and re-parse when you pull it out.
{
"activityId":"ACTIVITY_ID",
"user": {
"id":"USER_ID",
"name":"USER_NAME",
"aadObjectId":"AAD_OBJECT_ID",
"role":"user"
},
"bot": {
"id":"BOT_ID",
"name":"BOT_NAME"
},
"conversation": {
"conversationType":"personal",
"tenantId":"YOUR_TENANT_ID",
"id":"YOUR_CONVERSATION_ID"
},
"channelId":"msteams",
"locale":"en-US",
"serviceUrl":"https://smba.trafficmanager.net/amer/"
}
What you are looking for (I think) is conversationReference.conversation.id. Different channels are going to have different attributes in the conversation reference, but this ID should always be there.

Move mentioned user from a voice channel to another (discord.js) [duplicate]

I've gotten many errors in my code that I believe has been the result of mix-ups between GuildMembers and Users. Can someone explain the difference?
const user = message.mentions.users.first();
// TypeError: user.kick() is not a function
user.kick({ reason: 'spamming' });
// TypeError: user.ban() is not a function
user.ban({ reason: 'DM Advertising' });
// TypeError: message.author.hasPermission() is not a function
if (!message.author.hasPermission('ADMINISTRATOR')) return;
console.log(user.displayName); // undefined
// TypeError: message.member.createdAt() is not a function
embed.addField('Account Created', message.member.createdAt());
client.on('guildMemberUpdate', (oldMember, newMember) => {
console.log(`${newMember.tag} was updated`); // 'undefined was updated'
});
if (message.member.bot) return; // undefined
// TypeError: Cannot read property 'add' of undefined
user.roles.add(newRole)
const target = message.client.users.cache.get(args[0])
console.log(target.displayName) // undefined
From Official Discord.js Guide - Common Questions:
A lot of users get confused as to what the difference between Users and GuildMembers is. The simple answer is that a User represents a global Discord user and a GuildMember represents a Discord user on a specific server. That means only GuildMembers can have permissions, roles, and nicknames, for example, because all of these things are server-bound information that could be different on each server that user is in.
Many errors in the code in question occur because you are trying to call a guild specific function on a global user. For example, GuildMember.kick() and GuildMember.ban(). A very common mistake that leads to this is using the message.mentions.users collection. As the name suggests, this returns a collection of Users.
If you simply want, for example, the mentioned user's avatar, or maybe they're username and discriminator, it would work out fine. But it will lead to errors if you ever try to, for example, try to get the date they joined your server using GuildMember.joinedAt()
Luckily, there are many easy ways to circumvent this issue. For example, using MessageMentions.members (returns a collection of GuildMembers) instead of MessageMentions.users
const member = message.mentions.members.first()
member.ban() // no error here!
Another common workaround is using the Guild.member() method, which accepts a User object or ID!
const user = client.user // get the user object
const guild = client.guilds.cache.get('Guild ID') // get the guild object
const member = guild.member(user) // convert the User object to a GuildMember!
Other useful tricks to easily convert Users to GuildMembers include:
Using message.member instead of message.author
Using guild.members.cache.get() instead of client.users.cache.get()
Using guild.members.fetch() instead of client.users.fetch()
Using presence.member instead of presence.user
It's also very useful to remember if specific event parameters provide Users or GuildMembers. For example, both guildMemberAdd() and guildMemberUpdate pass GuildMembers, but messageReactionAdd(), guildBanAdd(), and typingStart() all pass Users.
While many GuildMember properties and methods are not available for a User, the same is true the other way around. For example, GuildMember.tag does not exist. However, converting a GuildMember to a User is much easier than converting a User to a GuildMember. This is because of GuildMember.user:
The user that this guild member instance represents
So, although GuildMember.tag will return undefined, GuildMember.user.tag will not!
Just want to add to Lioness100's answer, the following no longer seems to work
const member = guild.member(user);
Instead you can use:
const member = guild.members.fetch(user);
This returns a promise so don't forget to deal with that accordingly

Welcoming of Bot not working because of "Cannot read property 'find' of undefined"

Ok so I want my bot to welcome new users in a channel for welcoming, so I used find. Here is what I got so far:
client.on('guildMemberAdd', member => {
let guild = member.guild;
guild.channel.find('name','welcome','welcoming','greeting','general').send(`AYYY! Welcome ${member.user} to our Discord Server! Check out the FAQ, Info, and/or The Rules channels (if there is) for some documentation and support to help you get ready!`);
});
Expected result: Welcomes the user in the channel that was used find on.
Actual Result: Cannot read property 'find' of undefined.
I tried a lot of things, but the results are the same. Also, channels didn't not work, only channel.
I also don't believe you can use .find() to return multiple channels, since it always returns the first element it finds in the array.
You can, however, create another array that is a filter of guild.channels.cache based on channel names and then use .forEach() on that array to send a message to each of them like so:
function channelNamesFilter(channel) {
let channelNames = ['name','welcome','welcoming','greeting','general'];
if(channelNames.includes(channel.name)) {
return true;
}
return false;
}
let filteredChannels = guild.channels.cache.filter(channelNamesFilter);
filteredChannels.forEach(element => element.send('AYYY! Welcome ${member.user.name} to our Discord Server! Check out the FAQ, Info, and/or The Rules channels (if there is) for some documentation and support to help you get ready!'));
Notice too how I changed ${member.user} to ${member.user.name}, the first one is an object the second one is its name property in string form.
It's guild.channels with a s and you have to use the cache so your code would be:
client.on('guildMemberAdd', member => {
let guild = member.guild;
guild.channels.cache.find('name','welcome','welcoming','greeting','general').send(`AYYY! Welcome ${member.user} to our Discord Server! Check out the FAQ, Info, and/or The Rules channels (if there is) for some documentation and support to help you get ready!`);
});
Edit:
You can't find multiple channels. You have to put only one name.

Discord.js SetNickname Function Is Not Working

I am trying to make a bot that gives a role and sets nickname of it's user.
My goal is if someone types " -verify SomeNickname " on the text channel the bot will set their nickname as SomeNickname and give them a certain role.
mem.AddRole is working without any errors but .setNickname function is not working with anything.
The error is TypeError: mem.setNickname is not a function
This duplicate thread did not work for me: Change user nickname with discord.js
I also tried:
message.member.setNickname & message.author.setNickname &
client.on('message', message => {
if (message.content.startsWith('-verify')) {
message.author.setNickname({
nick: message.content.replace('-verify ', '')
});
}
});
so far.
My code is:
module.exports = bot => bot.registerCommand('verify', (message, args) => {
message.delete();
var title = args.join(' ');
var mem = message.member;
mem.addRole('560564037583241227').catch(console.error);
mem.setNickname(title);
}
The bot is giving the role without any problems but its not setting a nickname to the user.
Additional Info: Bot has every permission and im not trying to change server owner's nickname.
The message.member object looks like this:
As determined through the chat, your current code is using discord.io, not discord.js. These libraries are different, so that's the source of your various issues.
I'd recommend using discord.js from now on, but you may have to restructure your code a little bit. Documentation can be found here for future reference.
If you'd like to continue using discord.io, you can edit your question to be clearer, although from our conversation you don't intend to.

issue with creating role and channel automatically from private message with bot

Not sure how the create channel and create role isn't working inside the following code, towards the bottom. (EDIT: Nothing is sent to the console and nothing happens regardng the code. It is like it is entirely ignored.) This is a snippet from code that User A challenges User B. User B is messaged, alerting them that a challenge has been issued to them via a Private Message. If the challenge is accepted, I want the bot to 1)Make a role specifically for User A and User B named "User A vs User B" 2) take User A and User B and put them both into that new role and 3) Make a battlefield named "User A vs User B" inside a specific category inside the server the bot is on.
I am unsure if the problem lies in how the bot is trying to make the role and channel in a sever while the bot is talking to the user in a private message instead of on the server. I thought putting the "server" variable as the server ID would help but it doesn't seem to do anything after the accept message.
// Awaits reply from user
if (message.channel.id === '541736552582086656') return target.send("Do you accept the challenge? Please reply with 'accept' or 'deny'.")
.then((newmsg) => {
newmsg.channel.awaitMessages(response => response.content, {
max: 1,
time: 150000,
errors: ['time'],
}).then((collected) => {
// Grabs the first (and only) message from the collection.
const reply = collected.first();
if (reply.content === 'accept'){
reply.channel.send(`You have ***accepted *** the challenge from ${challenger}. Please wait while your battlefield is made...`);
message.author.send(`${target} has accepted your challenge! Please wait while the channel is made for your brawl...`)
/// Problems start here
function createChannel(message){
var server = "SERVER ID";
var name = `${target} vs ${challenger}`;
message.guild.createRole({
role: {
name: `${target} vs ${challenger}`,
color: "#00fffa",
permissions: [] }
}).then(role => {
target.addRole(role, name)
challenger.addRole(role, name)
.catch(error => client.catch(error))
}).catch(error => client.catch(error))
server.createChannel(Name, name).then(
(channel) => {
channel.setParent("CATEGORY ID")
})
} // problems end here
} else if (reply.content === 'deny') {
reply.channel.send("You have ***denied *** the challenge.")
} else {
reply.channel.send("Your response wasn't valid.");
}
})
})
}
I have been wondering if I need to go about making the channel and role in a different way since it is trying to be made from a private message and not inside the server..
Thanks for any and all help! I also apologize if I'm using stack overflow too much for problems like this... You guys are great at helping me see different ways to do things and what I'm doing wrong, so I am learning, but I don't want to feel like I'm abusing it too much.
I think the problem is the fact that you create a function called createChannel with the code to create a rol and channel, but you never call said function.
You can either call the function after you've declared it or (which is in my opinion better) you can remove the following lines
function createChannel(message){
} // problems end here

Resources