How can display roles and member count of roles - javascript

I am trying to make a command, with discord.js, that will display the roles of a guild and member count of each role! So far everything I am trying , it returns me all time to an error !
Here is the code I am trying:
const roles = message.guild.roles.cache.map(role => role).sort((a, b) => b.position - a.position).slice().join('')
I am struggling to find a way how to display member count for each role!
I have been trying this :
const size = message.guild.roles.cache.get(roles).members.map(m=>`${m}`).size;
But it is returning an error :
TypeError: Cannot read property 'members' of undefined
All I want to display is like the photo:

What you can do is fetch the server roles, and sort them from the highest position to the lowest and map them to look like you want.
Here's an example:
let roles = await message.guild.roles.fetch();
message.channel.send(
roles.cache.sort((a, b) => a.position - b.position).map((r) => `${r.name} - ${r.members.size}`),
{ split: true, code: true }
)
This should send the message like the one in the image

Use this:
await <message>.guild.roles.fetch(); //<message> is a placeholder for whatever variable you use for message
const roleArray = <message>.guild.roles.cache.array().sort((a, b) => b.position - a.position)
var members = roleArray.map((r) => {
members.push(r.members.size) //idk if this is right
});
//Now members and roleArray will have paired indexes (roleArray[0] has as many members as members[0])
Sorry if it doesn’t work, I sometimes mess up .toArray() and .array(), and I didn’t test it.

This would do it i guess
function getRoleCount() {
message.channel.send(message.guild.roles.cache.map(x => `${x.name} - ${x.members.size}`).join('\n'));
}
getRoleCount();
each element of message.channel.send(message.guild.roles.cache has name and members property which corresponds to the role name and members with the role. members.size returns the number of people who has the role. Therefore the output of the function would be
roleA - 10
roleB - 15
etc on every roles in the guild

Related

Is there a way to get a user's ID from a mention without them being in the guild?

I am trying to make an unban command by using mentions. If there's a way to get a user's ID by mention without them being in the actual guild I'm executing the command from, that'll be great.
When trying to execute, I get an error telling me that it cannot read property 'id' of undefined. But when I do it while the user is in the guild, it can read it just fine.
My code:
const Discord = require("discord.js");
module.exports = {
name: "unban",
aliases: [],
usage: "{prefix}unban <user>",
category: "moderation",
desc: "Unban a banned user.",
run: async (client, message, args) => {
let unbanned1 = message.mentions.users.first().id || args[0];
let unbanned = await client.users.fetch(unbanned1);
let ban = await message.guild.fetchBans();
// MESSAGES
if (!args[0]) {
return message.channel.send('❌ - Please specify a user to unban.')
}
if (!unbanned) {
return message.channel.send(`❌ - User not found.`)
}
if (!ban.get(unbanned.id)) {
return message.channel.send("❌ - This user hasn't been banned.")
}
// No author permissions
if (!message.member.hasPermission("BAN_MEMBERS")) {
return channel.send("❌ You do not have permissions to ban members.")
}
// No bot permissions
if (!message.guild.me.hasPermission("BAN_MEMBERS")) {
return channel.send("❌ I do not have permissions to ban members. Please contact a staff member")
}
var user = ban.get(unbanned1);
message.guild.members.unban(unbanned1);
const embed = new Discord.MessageEmbed()
.setColor("GREEN")
.setAuthor(user.user.username, user.user.displayAvatarURL({ dynamic: true }))
.setDescription(`${user.user.tag} got unbanned:`)
.setTitle("User Unbanned Successfully")
.addField(`By:`, `${message.author.tag}`, true)
.setThumbnail(user.user.displayAvatarURL({ dynamic: false }))
.setFooter(message.member.displayName, message.author.avatarURL({ dynamic: true }))
.setTimestamp()
message.channel.send(embed);
},
};
Thank you in advance.
You can use a regex to match and capture the ID of a user from the user mention pattern, which looks like this: /<#!?(\d{17,19})>/
<# - matches these characters literally
!? - optional "!"
(...) - captures everything inside for later use
\d - any digit
{17-19} - 17 to 19 of the preceding character (\d)
> - matches this character literally
You can execute the match with this code:
const match = args[0].match(/<#!?(\d{17,19})>/);
If nothing is found, this will return null. Otherwise, it will return an array with this structure:
[
'<#!id_here>',
'id_here',
index: 0,
input: '<#!id_here>',
groups: undefined
]
So, to get the ID, simply grab the second element (at index 1)
// I'm using the optional chaining operator (?.) in the below
// example, which requires node 14.0.0
// if you do not have this version, just separate the `match()` result
// into a separate variable
// and validate it exists before accessing match[1]
let unbanned1 = args[0].match(/<#!?(\d{17,19})>/)?.[1] || args[0];
I don't think it is possible to get user's id from mention if they are not in the guild. Since they are not GuildMembers and you can't mention them. (Yes there is a way to mention user that is not in a guild by using their id, but discord.js does not recognize that as a valid mention I think.)
Nice workaround would be to use the BanInfo since it contaions a User object. Get the id from there. If you want to unban users by their usernames, you can compare the username property of the User in BanInfo with the username that the person who sent the unban command specified.
But be aware that usernames are not unique, so it would probably be nice to also use the discriminator property of User.

How would I kick all the users that contain a phrase in their name?

Whats a good way to find all users to execute a kick on them if they all contained a phrase in their name like "ihatemelons" for example.
let server = message.guild.id
//grab all discord names
let list = client.guilds.cache.get(server)
console.log(`All Users In Guild: ${list}`)
list.members.cache.forEach(member => console.log(member.user.username));
//Regex term to search
let re = (/_/ig)
//Search all of them
let usersFound = list.members.cache.forEach.match(re)(member => console.log(member.user.username))
list.members.cache.forEach(usersFound => console.log(member.user.username));
//What to do with the users that have the phrase in their name
message.reply(`Found:${usersFound}`)
Except I am stuck on where I search because
let usersFound = list.members.cache.forEach.match(re)(member => console.log(member.user.username)) doesnt work
Well you can use a regex to find the phrases you don't like, for example if you don't like the word creepy in username, you can simply do this:
let regex = /creepy/ig
regex.test("creepyUsername"); // Outputs true
for more info about regex:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
message.guild.members.cache.filter(member => member.user.username.includes('ihatemelons'))
Since GuildMemberManager.cache returns a Collection, you can utilise the methods provided by Collection and Map. Collection.filter() acts like Array.filter(), but returns a Collection instead.
Edit
This works for me:
const members = await message.guild.members.fetch();
let usersFound = members.filter(member => member.user.username.includes('ihatemelons'));
// OR: case-insensitive:
let usersFound = members.filter(member => /ihatemelons/i.test(member.user.username));
// OR
let usersFound = members.filter(member => member.user.username.toLowerCase().includes('ihatemelons'));
usersFound.forEach(member => console.log(member.user.username));
Make sure you have enabled the privileged intent for receiving full member lists in the Discord Developer Portal.

firestore Check if id exists against an array of ids

I developing a simple chat applicaiton for my website using firebase firestore. where every chat session has an id
provided i have an array of ids
chat_sessions = ["q93XhadA9QQLu6X8yfZB", "YXEYISEI8b2iixCcP3VO", "GXrSZbtrmN5NcrtvjFYp"]
I want to get all document whose id is equal to any of the id's in the chat_sessions object using the code below.
return this.afs
.collection('chats', ref => ref.where('uid','in_array',chat_sessions)).snapshotChanges...
but I am not getting any results.
I come from a PHP/MYSQL background
the PHP equivalent of what i am trying to achieve will be sth like this in PHP
if(in_array(uid,chat_sessions)){
get(doc/uid)
}
can anyone help with the right query where we check for document id against a list of ids in an array? Thank You!
Thank you #frank van Puffelen. You were almost right. I should have used in instead of in_array
ref.where(firebase.firestore.FieldPath.documentId(),'in_array',chat_sessions)
did not work. Instead I replaced in_array with in :
ref.where(firebase.firestore.FieldPath.documentId(),'in',chat_sessions)
This worked! Thank you
Your query is:
ref.where('uid','in_array',chat_sessions)
This checks a field called uid in each document against the values of the chat_sessions.
It seems that instead you want to the check the ID of each document against the array, which you can do with:
ref.where(firebase.firestore.FieldPath.documentId(),'in_array',chat_sessions)
I found something else on firestore i.e "array-contains-any" for this case.
Maybe it's updated now.
UPDATE
Hi, firebase did some update recently, so for do it I found out this method
`
const [products, setProduct] = useState([]);
const ids = ['H11LlJsh3sObwORZhA0b','om9m0lU9HYWyOJZKvEdi','1AoHyHuSFcF01zoyXyTD','6xoBlxsRXUoyzBUcWl0F',
'GJqthlmBGZaFAJqtC2jK','QNT3PxMfhNGg1RZnuqcq','RZgGoFZHyDAYaVZJWxGk','g4UO5P0EgtEqJnawwhXX','gyrZm8p0cEgJdDvTuB1g','mrscldfeYlkaSF151MpI',]
useEffect(() => {
const saveFirebaseTodos = [];
ids.forEach((element) => {
fetchMyAPI()
async function fetchMyAPI() {
const q = query(collection(db, "a"), where('__name__', '==', element));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
saveFirebaseTodos.push(({id: doc.id, ...doc.data()}));
/*console.log(doc.id, " => ", doc.data());*/
if (ids.length == saveFirebaseTodos.length) {
setProduct(saveFirebaseTodos)
}
});
}})
}, [])`
In this way, you can check how many element in arrays you want (bypassing 10 elements limit of firebase).
Hope can help anyone :D

Check if particular value exists in my users node

I iterate throught all the users node, I just want to send notifications to the users who have shop as a value inside the document, if there is users that dont have this attribute inside the document I dont want to send them a notification
exports.rememberToOpenStore = functions.pubsub.schedule('30 09 * * *').onRun(async (context) => {
var db = admin.firestore();
let snap = await db.collection('user').get();
return snap.forEach((doc) => {
if(doc.data().shop !== null){
const deviceToken = doc.data().deviceToken
const payload = {
notification: {
title: "Good morning ! 🌅😊",
body: "Remember to open your store."
}
}
return admin.messaging().sendToDevice(deviceToken,payload)
}
return null;
});
});
I want to know if this
if(doc.data().shop !== null)
will do the trick to know which user has or not that attribute
Is there a better way to do this with a where query with something like
let snap = await db.collection('user').where("shop" "!=", null).get();
to just get users that have that shop value inside the docuement ?
Thanks !
I'm unsure about the values that shop may have, but according to the documentation you could orderBy a field and if it doesn't exist it will not be returned. Thus, querying Firestore ordering by the field shop will not return the documents that don't contain said field.
The query should be something like this:
db.collection('user').orderBy('shop').get()
Another option would be creating the field for all the documents and assigning it a null value. This way you could also retrieve the documents that have said field.
In this case the query should be something like this:
db.collection('user'),where('shop', '!=', null).get()

Using some sort of loop to add to a string

I’m trying to make a shop command that lists the items that I have added to the shop via another command. I tried to use a for loop to add to the string, but I had no luck with that because the values were undefined For some reason. At this point, I’ve switched to forEach in an attempt to try and make this work, but instead of each value being undefined, it only lists 1 of the 2 items saved in the database.
I am using Enmap to store the shop items.
I filter the shop items using the .filter() function which returns an Enmap (map)
Expected Behavior: The command properly lists all items in the shop (in this case 2 items) and all of their values
Actual Behavior: The embed only shows 1/2 of the items.
const Discord = require('discord.js');
module.exports = {
id: 'shop',
aliases: ['buythings', 'linkcoinshop', 'edward'],
channels: 'guild',
exec: async (call) => {
try {
let filter = await call.client.shopData.filter(find => {
return find.guildID === call.message.guild.id && find.forSale === true
});
if(filter.size === 0) return call.message.channel.send(`There are no items for sale right now.`)
let embedDesc = '';
console.log(filter)
filter.forEach(found => {
embedDesc += `**__${found.itemName}__** \nDescription: ${found.itemDesc} \nCost: ${found.itemCost} \nQuantity: ${found.itemQuan} \n\n`
})
const linkCoin = call.client.emojis.get('670675326837194782');
const shopEmbed = new Discord.RichEmbed()
.setTitle(`${linkCoin} LinkCoins Shop`)
.setColor('BLURPLE')
.setDescription(embedDesc);
//.setDescription(`🔷: **__Diamond Role__** \nDescription: Gives access to diamond only perks including special giveaways and more! \nCost: 1500${linkCoin} \nQuantity: ♾️ \n\n 💠: **__Diamond + Role__** \nDescription: Access to all perks that Diamond gets you, but with extra abilities such as your own personal voice chats. \n`)
call.message.channel.send(`Click on the reactions below to purchase.`)
call.message.channel.send(shopEmbed)
} catch(error) {
call.message.channel.send(`Oops! That was an error! The issue has been reported to the adminstration team`);
console.log(error);
}
}
};
If anybody has any suggestions of a better way to do this, or just a way to make this work, please let me know. Thanks!
Always create the minimum amount of code to illustrate your problem. It makes it easier for people to help you, and 8/10 times you will solve it yourself once you extract and isolate your problem.
Sounds like: how do I turn an array of objects into a string containing a list of the object properties?
Looks like you want to do this?
filter.reduce((prev, found) => `${prev}**__${found.itemName}__** \nDescription: ${found.itemDesc} \nCost: ${found.itemCost} \nQuantity: ${found.itemQuan} \n\n`, '')
Test case:
const filter = [
{
itemCost: 5,
itemName: 'snt',
itemDesc: 'desc',
itemQuan: 8
},
{
itemCost: 3,
itemName: 'another',
itemDesc: 'desc2',
itemQuan: 10
}
]
console.log(
filter.reduce(
(prev, found) =>
`${prev}**__${found.itemName}__** \nDescription: ${found.itemDesc} \nCost: ${found.itemCost} \nQuantity: ${found.itemQuan} \n\n`,
''
)
)
Output:
➜ t test.ts
**__snt__**
Description: desc
Cost: 5
Quantity: 8
**__another__**
Description: desc2
Cost: 3
Quantity: 10
This should work with Enmap. Per the API Docs:
enmap.reduce(fn, [initialValue]) ⇒ *
Identical to Array.reduce().
Turns out, there was nothing wrong with the filter or the forEach loop.
Although .reduce() works in my testing, I will continue to use forEach.
My problem was I was setting it all as the same key, which was causing Enmap to overwrite the values, hence only showing 1 of the things I added.
Thanks for all your help!
I will leave Josh's answer as the correct one since his method would work as well.

Categories

Resources