I am looking to get the id of every role a user has. the user being the message author in my case.
i've tried various things suggested such as let roles = message.author.roles.id = [] and message.guild.roles.fetch() however nether seem to do what I need.
var XPRole = {};
if (fs.existsSync('noxprole.json')) {
XPRole = jsonfile.readFileSync('noxprole.json');
}
client.on('message', async (message) => {
const { member } = message;
if (message.author.bot) return;
if (message.guild.id in XPRole === false) {
XPRole[message.guild.id] = {};
}
const RoleID = XPRole[message.guild.id];
if ('...' in RoleID) {
return;
}
Any help would be appreciated.
The intention of this code is to compare a users roles against a JSON file containing a list of roles that wont earn xp when typing.
As Elitezen mentioned in their comment, message.author is a User and Users don't have roles, only GuildMembers. You also can't use message.guild.roles as it returns a manager of the roles belonging to this guild, not just those belonging to the member.
You can however get the author of a message as a guild member by using the message.member property. Now, that you have the member, you can get the roles of them by accessing the member's roles. As the roles property returns a manager, you need to access its cache property:
const roles = message.member.roles.cache;
It returns a collection of the roles of this member, and collections have a .map() method that maps each item to another value into an array. It means that you can easily create an array of role IDs this member has using roles.map:
const memberRoleIDs = roles.map((role) => role.id);
// => ['772088200214723861', '809320713752256548', '8184301957544091683']
As you can see, memberRoleIDs contains all the role IDs the member has.
I'm not sure how you store the role IDs in XPRole[message.guild.id]. It seems you store it as an object and the IDs are the keys. In that case, you can use the Array#some() method that tests if at least one element in the array passes the test implemented by the callback function.
So, if your XPRole[message.guild.id] object with IDs as keys, you can simply compare these keys to the array of role IDs. Check and run the following snippet:
let message = {
guild: {
id: 'guildID'
}
}
const memberRoleIDs = [
'7720882002147238612',
'8093207137522565483',
'8093207137522565481'
];
let XPRole = {
'guildID': {
'7437501734702175013': { /**** */ },
'8093207137522565481': { /**** */ },
'9483513543347850432': { /**** */ },
}
}
const containsRole = memberRoleIDs.some(id => id in XPRole[message.guild.id]);
// returns true as 8093207137522565481 is in both
console.log({ containsRole });
If you instead store an array of role IDs like in the following example, you can still use the same some() method but with a different callback, one that checks if any of the user role IDs is included in your XPRole[message.guild.id] array:
let message = {
guild: {
id: 'guildID'
}
}
const memberRoleIDs = [
'7720882002147238612',
'8093207137522565483',
'8093207137522565481'
];
let XPRole = {
'guildID': [
'7437501734702175013',
'8093207137522565481',
'9483513543347850432',
]
}
const containsRole = memberRoleIDs.some(id => XPRole[message.guild.id].includes(id));
// returns true as 8093207137522565481 is in both
console.log({ containsRole });
Here is the full code:
let XPRole = {};
if (fs.existsSync('noxprole.json')) {
XPRole = jsonfile.readFileSync('noxprole.json');
}
client.on('message', async (message) => {
if (message.author.bot) return;
const roles = message.member.roles.cache;
const memberRoleIDs = roles.map((role) => role.id);
if (message.guild.id in XPRole === false) {
XPRole[message.guild.id] = {};
}
if (memberRoleIDs.some((id) => id in XPRole[message.guild.id])) {
return console.log('member has at least one role id included in XPRole');
}
});
You can iterate through all the roles of the member. So you will need to collect the GuildMember object instead of the User.
const RoleID = XPRole[message.guild.id];
for(var memberRoleID in message.member.roles.cache.array()) {
if (RoleID.includes(message.member.roles.cache.array()[memberRoleID].id)) {
return;
}
}
Related
So, I wanted to add command /custom and after that, user would enter they nicknames through messages. Bot should check if ther nickname is in game (async function checkIfSummonerExist(m)) and if it does exist, bot should collect their name and data and push to array (async function getSummonerProfile(m.content)). Now I wanted to add bot reactions to those messages, if nickname exist, it should add one reaction (for example thumbs up), and if name does not exist one should add thumbs down. So I tried with m.react(), but it does not work. I also tried with m.reply("User approved")but I don't get reply. I am new to making discord bot.
const { SlashCommandBuilder } = require("#discordjs/builders");
const { getSummonerProfile } = require("./../functions/summonerData");
const { calculateRank } = require("./../functions/calculateRank");
let arrayOfSummoners = [];
async function checkIfSummonerExist(m) {
const test = await getSummonerProfile(m.content);
if (test) {
return true;
} else {
return false;
}
}
module.exports = {
data: new SlashCommandBuilder()
.setName("custom")
.setDescription(
"Enter the name of the user."
),
async execute(interaction) {
await interaction.deferReply();
// `m` is a message object that will be passed through the filter function
const filter = (m) => checkIfSummonerExist(m);
const collector = interaction.channel.createMessageCollector({
filter,
time: 15000,
});
collector.on("collect", (m) => {
m.reply('User approved');
m.react('😄');
arrayOfSummoners.push(getSummonerProfile(m.content));
});
collector.on("end", (collected) => {
// return interaction.editReply(`Collected ${collected.size} items`);
// calculateRank(arrayOfSummoners);
});
// return interaction.editReply();
},
};
This is the code where I add data to firestore.
How can I check if idEveniment field already exist in collection?
And if exist I dont want to add the new collection.
Maybe return an error ?
import { firestore } from 'firebase';
// Add Eveniment
export const addEveniment = data => async(dispatch, getState, {getFirestore}) => {
const firestore = getFirestore();
const userId = getState().firebase.auth.uid;
dispatch({type: actions.ADD_EVENIMENT_START});
try {
const res = await firestore.collection('evenimente').doc(userId).get();
const newEveniment = {
idEveniment: data.idEveniment,
eveniment: data.eveniment,
}
if(!res.data()) {
firestore.collection('evenimente').doc(userId).set({
evenimente: [newEveniment],
});
} else {
firestore.collection('evenimente').doc(userId).update({
evenimente: [...res.data().evenimente, newEveniment],
});
}
dispatch({type: actions.ADD_EVENIMENT_SUCCESS});
return true;
} catch(err) {
dispatch({type: actions.ADD_EVENIMENT_FAIL, payload: err.message})
}
}
In your current data structure you can't check for documents with a specific value of idEveniment. You can use array-contains to check array membership but only if you specify the combinarion of idEveniment and eveniment.
If you want to be able to check just on the value of idEveniment, consider adding a field idEveniments to each document with just that value. Then you can use array-contains for the existing of a specific idEveniment value in the idEveniments array:
const evenimentesRef = firebase.firestore().collection("evenimente");
const query = evenimentesRef.where("idEveniments", "array-contains", "376342").limit(1);
query.get().then((snapshot) => {
if (!snapshot.empty()) {
... a document with the value already exists
}
});
I want get info about reactions but i can't. I need get reaction and authors this reactions from old message without listeners or something.
This code make something similar https://gist.github.com/acollierr17/c9e7aaf9eba97d8659b59395b5f2046d but don't work for me, var is empty. But i can get message m.channel.fetchMessage(ID)
I don't understand why this does not work, although the message is received to var. How collect all reactions and their authors of message to array?
I try this and few other ways.
if(calcreact == 1 && msg.content.startsWith('/calcreact')) { //start
calcreact = 0; // защита от флуда
let msgid = finddata(msg.content);
//let channel = 709517297664131082;
msg.channel.fetchMessage(msgid)
.then(m => {
//console.log('Message:', message.content);
let reactions = m.reactions;
let reaction = reactions.first();
let users = reaction.users.map((u) => u.toString());
console.log(users);
//console.log(m.reactions.fetch());
//console.log(m.reactions.forEach((reaction) => {}));
m.reactions.forEach((reaction) => console.log(reaction));
m.reactions.forEach((reaction) => console.log(reaction.users));
m.reactions.forEach((reaction) => console.log(reaction.users.map((u) => u.toString())) );
//console.log('Reactions:', );
});
setTimeout(antiflood, 500, 'calcreact');
} //end
From m.reactions.forEach((reaction) => console.log(reaction)); i can get huge info "array" and in marked current reaction(It seems to me https://i.imgur.com/OazszNR.png) but deep (users) empty. This is horrible...
The function bellow groups reactions by users, like this:
{
userId1: ['reactionId1', 'reactionId2'],
userId2: ['reactionId1', 'reactionId2'],
...
}
You can adapt this to get the users and reactions from messages, or any context you like.
OBS: It was written in TypeScript, but if you remove the typing, it turns into JavaScript.
Function:
import { MessageReaction } from "discord.js";
interface IReactionsByUsers {
[userId: string]: Array<string>;
}
DiscordClient.on("messageReactionAdd", (reaction: MessageReaction) => {
const reducer = (acc: IReactionsByUsers, cur: [string, MessageReaction]) => {
const [reactionId, reaction] = cur;
const usersIds = [...reaction.users.cache].map(([userId]) => userId);
for (const userId of usersIds) {
if (acc[userId]) {
acc[userId].push(reactionId);
} else {
acc[userId] = [reactionId];
}
}
return acc;
};
const messageReactions = [...reaction.message.reactions.cache];
const reactionByUsers = messageReactions.reduce(
reducer,
{} as IReactionsByUsers
);
return reactionByUsers;
});
use the client.on("messageReactionAdd" method and save the reactions in an array.
I want to send a notification to all users who are confirmed guests when the object confirmedGuests is created in the Firebase Realtime Database.
So, I first create an array of all the users from confirmedGuests object. Then, I iterate through all these users and push their deviceTokens to an array of deviceTokens. The array allDeviceTokens is expected to be the array of device tokens of all users in confirmedGuests.
However, when confirmedGuests object is created, the function returns an error.
Below is my cloud function
exports.sendNotification = functions.database
.ref('/feed/{pushId}/confirmedGuests')
.onCreate((snapshot, context) => {
const pushId = context.params.pushId;
if (!pushId) {
return console.log('missing mandatory params for sending push.')
}
let allDeviceTokens = []
let guestIds = []
const payload = {
notification: {
title: 'Your request has been confirmed!',
body: `Tap to open`
},
data: {
taskId: pushId,
notifType: 'OPEN_DETAILS', // To tell the app what kind of notification this is.
}
};
let confGuestsData = snapshot.val();
let confGuestItems = Object.keys(confGuestsData).map(function(key) {
return confGuestsData[key];
});
confGuestItems.map(guest => {
guestIds.push(guest.id)
})
for(let i=0; i<guestIds.length; i++){
let userId = guestIds[i]
admin.database().ref(`/users/${userId}/deviceTokens`).once('value', (tokenSnapshot) => {
let userData = tokenSnapshot.val();
let userItem = Object.keys(userData).map(function(key) {
return userData[key];
});
userItem.map(item => allDeviceTokens.push(item))
})
}
return admin.messaging().sendToDevice(allDeviceTokens, payload);
});
You're loading each user's device tokens from the realtime database with:
admin.database().ref(`/users/${userId}/deviceTokens`).once('value', (tokenSnapshot) => {
This load operation happens asynchronously. This means that by the time the admin.messaging().sendToDevice(allDeviceTokens, payload) calls runs, the tokens haven't been loaded yet.
To fix this you'll need to wait until all tokens have loaded, before calling sendToDevice(). The common approach for this is to use Promise.all()
let promises = [];
for(let i=0; i<guestIds.length; i++){
let userId = guestIds[i]
let promise = admin.database().ref(`/users/${userId}/deviceTokens`).once('value', (tokenSnapshot) => {
let userData = tokenSnapshot.val();
let userItem = Object.keys(userData).map(function(key) {
return userData[key];
});
userItem.map(item => allDeviceTokens.push(item))
return true;
})
promises.push(promise);
}
return Promise.all(promises).then(() => {
return admin.messaging().sendToDevice(allDeviceTokens, payload);
})
I have in firebase firestore a Collection named users created with docs of unique id.
Now I would like to push them in an Array.
(In the usersCollection there are 3 users stored with the currentUser.uid)
Example:
fb.usersCollection.where("state", "==", 'online').get().then(querySnapshot => {
querySnapshot.forEach((doc) => {
const userName = doc.data().name
this.markerMy = { name: userName }
})
// push userName inside randomArray
const randomArray = []
randomArray.push(this.markerMy)
I only get it so that I can push one user inside the Array, but not more.
You should declare randomArray before fb.usersCollection and call the push operation inside the callback as follows :
const randomArray = []
fb.usersCollection.where("state", "==", 'online').get().then(querySnapshot => {
querySnapshot.forEach((doc) => {
const userName = doc.data().name
this.markerMy = {
name: userName
}
randomArray.push(this.markerMy)
})
});