?members command for my discord bot - discord.js - discord.js

So I've been trying to create a ?members command which lists all the users with a role.
So far I've got this:
if (message.content.startsWith("?members")) {
let roleName = message.content.split(" ").slice(1).join(" ");
let membersWithRole = message.guild.members.filter(member => {
return member.roles.find("name", roleName);
}).map(member => {
return member.user.username;
})
const embed = new Discord.RichEmbed({
"title": `Members in ${roleName}`,
"description": membersWithRole.join("\n"),
"color": 0xFFFF
});
return message.channel.send(embed);
}
So, it works if you type the exact name of the role, but not when you ping it or type the first word. I've been trying for hours to figure out how to do it, and I figured I should ask for help.
Thanks in advance!

Pings get translated into a code as they come through, there is a lot of information on how to parse them in the official guide After it's parsed into a role id you can just use members.roles.get() because that is what they are indexed by.
As for finding a partial name, for that you are going to have to run a function on your find and use String.includes.
return member.roles.find(role => role.name.includes(roleName));
This will also work for find the whole name of course, so it can replace your existing line.
However, this may result in more than one role. This is also true for searching by the entire role name, however, as there are no restrictions on duplicate named roles. For this you may want to invert you design and search through message.guild.roles first for any matching roles, then search for members with the roles found.

Related

How do I get someones username AND tag? (Discord.js)

So, I'm trying to make a serverInfo command as you can see below
let embed = new Discord.MessageEmbed()
.setColor("GREEN")
.setTitle("Server Information")
.setDescription(`Server Name: **${message.guild.name}** \n ────────────────── \n Member Count: **${message.guild.memberCount}** \n ────────────────── \n Server ID: **${message.guild.id}** \n ──────────────────`)
.setTimestamp()
.setFooter(`Ran by: ${message.author.username.id}`)
message.channel.send(embed)
For my result, I get "undefiened"
anyone know the solution to this? (.setFooter)
message.author.tag for get the user with tag (JohnDoe#0000)
message.author.user for get the user
message.author.user.username for get the Username
message.author.user.id for get the ID
Simple (:
To get the complete tag of a user, you can just use .tag after message.author.
In your code, you're trying to get the username but you put .id after it so this is why you get "undefined".
The ID isn't the numbers with the hashtag, it's the user ID and the tag is the username plus the numbers with the hashtag.
⠀⠀⠀↱ John Doe#3040 ↰
Username⠀⠀⠀⠀ ⠀⠀Numbers
↳⠀⠀⠀⠀⠀⠀⠀⠀Tag⠀⠀⠀⠀⠀⠀⠀ ↲
So, to get the username and tag, just do this:
//say it’s called msg instead of message
var tag = msg.author.tag;
var username = msg.author.id;
//tag would return the user's tag, and as someone else stated in a comment in a previous answer, author returns a user, which itself doesn't have a user property because it is the user object
Also just a quick tip: since it’s server info command, you might want to put some information about the user that’s exclusive to that guild (nickname, roles, permissions), and for that, you can use msg.member which returns a GuildMember, which has a user property, and many more, like member.displayName and member.roles

Alternative Ways to Define Users in Discord.JS

So to define users for things like displaying avatars, etc. i've been using this;
var user = message.mentions.users.first() || message.author;
But i've been trying to figure out how people have been able to define users without mentions. Example - my command requires me to tag someone whereas Dyno can do it with partial names. Any tips would be great, thanks!
An easy way to do so would probably be using the .find() function, where you can search for a certain object based on a method.
For example, if we were to have an args variable in our callback (Very easy to do so using a proper command handler - I'd suggest looking for tutorials if you aren't familiar with command handlers), and we were to ask a user to pass in a member's name, we could very easily get the user object using:
const user = message.guild.users.cache.find(user => user.username === args[0]);
// Keep in mind, 'user' is just a variable I've defined. It could also be 'monke => monke.username' if you wish.
Or, if we were to ask for their ID, we could use the .get() function to get the user object by ID:
const user = message.guild.users.cache.get(args[0]);
Do keep in mind it's not the greatest to have these kinds of object getting functions, as there are always multiple conflicts that could occur whilst getting the object, such as if there are multiple users with the same name/tag. I'd highly recommend sticking to your mention-based user objects, as it's the most accurate and non-conflicting method.
Every guild has a list of members which you can search through by enabling the Server Members Intent for your bot via the Discord Developer Portal. Once you have done that, you can fetch a collection of all members of a guild by doing
guild.members.cache;
You can then search this collection to find a member based on a search query using .includes(), .filter() or something similar. For example:
let query = "something";
let list = guild.members.cache.filter(member => member.user.username.includes(query));
console.log(Object.entries(list));
// expected output: list of all server members who's usernames contain "something"
You could also use the .find() method (since a collection is a map) to return a member with an exact username:
let member = guild.members.cache.find(member => member.user.username === query);
console.log(member.tag);
// expected output: tag of the user who's username is "something"
This is as simple as that:
var user = message.guild.members.cache.find(u => u.user.username.toUpperCase() === args.join(" ") || u.user.username.toLowerCase() === args.join(" ") || u.user.username === args.join(" "))
This will find the user on the current guild but you can also search your bot for this user by doing:
var user = client.users.cache.find(u => u.username.toUpperCase() === args.join(" ") || u.username.toLowerCase() === args.join(" ") || u.username === args.join(" "))
I have to assume that you already defined args and client. The example above will find users just by typing their name. toUpperCase means if you type the username in uppercase letters it will find the users anyways. toLowerCase means if you type the username in lowercase letters it will find the user as well. And you could also just type the username as it is. || means or so you can decide how you write the username, it will be found anyways.

How can i make a guild-side variable using Discord.js

im trying to make a server/guild side variable for my bot (have a variable that has a different value in each server). I dont know how to make that so i really need help... How can i get a variable to have a different value in each server?
You should use a discord.js Collection, which is:
A Map with additional utility methods. This is used throughout discord.js rather than Arrays for anything that has an ID, for significantly improved performance and ease-of-use.
A Map object holds key-value pairs and remembers the original insertion order of the keys. Any value may be used as either a key or a value. Here's a quick demo:
// let's say we had two people: John and Sarah
const people = new Map();
// each of them were a different age
people.set('John', 25); // in this example, 'John' is the key, and 25 is the value
people.set('Sarah', 19); // in this example, 'Sarah' is the key, and 25 is the value
// each person has an individual age
// you can `get()` the key, and it will return the value
console.log(`Sarah is ${people.get('Sarah')} years old.`);
console.log(`John is ${people.get('John')} years old.`);
You can use this type of format to create a collection with each key being a different guild ID, and each value being... whatever you want. Here's an example:
// const { Collection } = require('discord.js');
const guilds = new Collection();
// put some data in an object as the key
guilds.set("Guild ID", {
name: "Guild Name",
welcomeMsg: "Welcome new person!",
welcomeChannel: "...",
blacklistedIDs: ["123456", "67890"],
});
client.on("guildMemberAdd", (member) => {
const guild = guilds.get(member.guild.id); // get the collection element via guild id
if (!guild) return;
// then access all its data!
console.log(`Somebody joined ${guild.name}`);
if (guild.blacklistedIDs.includes(member.id)) return member.kick();
guild.welcomeChannel.send(guild.welcomeMsg);
});
I believe Tin Nguyen posted this idea as a comment, I am just elaborating on that. To achieve what you want, you can use what is known as a "data dictionary" which is basically just a file storing a list of something.
For your specific use case, you can use a simple JSON file to store your variables. For each guild that your bot is in, you can add a new object to a list of objects in a local JSON file called variable.json for example.
Here is an idea of what it might look like:
[
{
"guild": "INSERT GUILD ID",
"value": "INSERT VARIABLE VALUE"
},
]
guild will store the id of the guild, so you can identify the correct value. To get the value stored in value for a certain guild, all you have to do is loop through the JSON file, and find the object with the correct guild ID:
const variables = require("variable.json"); //imports the JSON data
const value; //creates a new variable
for (i = 0; i < variables.length; i++) { //loops through the guilds
if (variables[i].guild === message.guild.id) { //if the IDs are the same...
value = variables[i].value; //...sets "value" to the retrieved value
}
}
This of course relies on the fact that your bot also adds each guild it joins to the list. To do this, you can use the guildCreate event. Documentation for this can be found here.

Is there an easy way to mass-remove a user's role with a Discord.JS bot?

I've got a verification bot for my server with linked roles. I've currently got it to remove all roles manually one by one, but of course this is inefficient and it only works for about 5/6 roles before stopping for a few seconds and continuing. What I'd like to try is some sort of discUser.removeRoles kind of thing, if that's possible.
Or is there a way to only try removing a role if the person has it? My code just does discuser.removeRole for every binded rank.
UPDATE
I got a notification about this question, so wanted to update it with a new solution for anyone else who finds this:
Create a table of your role ids. (e.g var giveThese = [])
guildMember.roles.add(giveThese,"Reason / Description"
For removing, you can replace roles.add with roles.remove
From what I understand from the question you're looping through every member of the guild and removing the role from each one of them.
To me, the most efficient way to do it is to take from the role the list of the members that have it (with Role.members) and then looping through that list.
You can do something like this:
let roleID = '1234...'
let role = guild.roles.fetch(roleID).then(role => {
role.members.forEach(member => member.roles.remove(roleID))
})
This is the most efficient way I can think for doing that since Discord currently has no way of "bulk removing" roles from users.
I was able to figure out a solution by looping over an external json file that holds all of the roles' data.
In the main file where you are trying to remove the roles, use a for in loop that loops over the json file containing all of the role names. Within the loop put the remove role method in there.
Here's an example of the .json file:
[
{
"role_name": "very slightly red",
"color": "#ffcccc",
"color_tier": "vs"
},
{
"role_name": "very slightly orange",
"color": "#ffedcc",
"color_tier": "vs"
},
{
"role_name": "very slightly yellow",
"color": "#ffffcc",
"color_tier": "vs"
}
]
And here's the code that removes the roles in bulk:
const vs_json = require("../vs_colors.json");
for (var key in vs_json) {
if (vs_json.hasOwnProperty(key)) {
console.log(
key +
" -> " +
vs_json[key].role_name
);
memberData.roles.remove(
getRole(
vs_json[key].role_name
)
);
}
}

RestFB: Getting list of users who liked a post

I need to get the name of each like on each post on a group page. Since I first have to get some data from the original post, I'm trying to make a connection then iterate through the likes and get a list of the users who liked each post. Here's what I have:
Connection<Likes> feedLikes = postFeed.fetchConnection(id+"/likes", Likes.class, Parameter.with("fields","from,actions,type"));
// Get the iterator
Iterator<List<Likes>> likeIt = feedLikes.iterator();
while(likeIt.hasNext()) {
List<Likes> likeFeed = likeIt.next();
for (Likes currLike: likeFeed) {
String ObjectId = id;
String LikeUserId = currLike.getId();
String LikeUserName = currLike.getName();
like_data.add(new String[] {ObjectId, LikeUserId, LikeUserName});
}
}
This doesn't work and I'm a little stuck on why. I know the username is stored in Likes.LikeItem but I can't even get to that step so far. Does anyone have any idea what I'm missing?
According to the Facebook reference this is not possible (https://developers.facebook.com/docs/graph-api/reference/v3.2/object/likes):
A User or Page can only query their own likes. Other Users'or Pages' likes are unavailable due to privacy concerns.
Only aggregated counts using total_count with the summary parameter are available for Post likes.

Resources