Discord.js V14 Cron fetch all guild members from specified server and retrieve their details - discord

My goal is to have a file run every few minutes on a schedule(cron). The cron isn't the issue, the issue is when I try and retrieve the members, I get Collection(0) [Map] {} Which is odd, there are members and my intents are set correctly.
const dotenvFlow = require('dotenv-flow');
const { Client, Partials, GatewayIntentBits } = require('discord.js');
dotenvFlow.config();
// Create a new client instance
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildIntegrations, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.DirectMessageTyping, GatewayIntentBits.DirectMessages], partials: [Partials.Channel] });
// Get the guild object
async function updateMembers() {
console.log("Starting...")
const guild = await client.guilds.fetch(process.env.hostDiscordServer);
// Get the members of the guild
const members = guild.members.cache;
// Insert or update each member in the database
members.forEach(member => {
// Check if the member belongs to the specified guild
if (member.guild.id === guild.id) {
// Get the member's premium role
const pRole = member.roles.cache.find(role => [process.env.pPremiumRole1, process.env.pPremiumRole2, process.env.pPremiumRole3].includes(role.name))?.name;
console.log("Inserting into DB")
// Insert or update the member's record in the database
console.log(member.id)
console.log(pRole)
}
});
}
// Log in to Discord with your client's token
client.login(process.env.DISCORD_TOKEN);
// Start the code
updateMembers();

You are iterating through the cached members of the guild.
If you want to iterate through all members (even the uncached) you need to fetch them first.
You just need to replace
const members = guild.members.cache;
with
const members = await guild.members.fetch();
discord.js docs
EDIT: I would also recommend changing
updateMembers();
to
client.once("ready", updateMembers);
so that the code only runs when the bot ready.
(Thanks to #Zsolt Meszaros for correcting me on that one)

Related

How to send an embed message to a different channel in interactions?

How to send a separate embed message to a channel different from where the slash command was executed? My current code is the following block.
const { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder, Guild } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('arrest')
.setDescription('puts the member to jail')
.addUserOption(option =>
option
.setName('target')
.setDescription('The member to arrest')
.setRequired(true))
.addStringOption(option =>
option
.setName('reason')
.setDescription('The reason for arrest'))
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers),
async execute(interaction) {
const messageEmbed = new EmbedBuilder()
.setTitle('ARRESTED!')
.setDescription(`***${interaction.options.getUser('target').tag}*** *broke a leg. Oops.*`)
.setColor(0xBD7A21)
.setImage('https://eca.astrookai.repl.co/media/arrest.gif')
await interaction.reply({embeds: [ messageEmbed ]});
},
};
Sending a separate embed object to a different channel is intended for channel logging for moderation actions in the server and I would like to know how to achieve this, thank you.
You can use <channel>.send() for this. In which <channel> is your channel object. You can get the channel in a multiple of different ways but this is probably the easiest:
logChannel = <interaction>.guild.channels.fetch(SNOWFLAKE_ID)
Then, you can send your embed to the logchannel like so:
logChannel.send({ embeds: [YOUR_EMBED] });
To account for every command, the easiest way is to do this in your interactionCreate event
If you need more context, you can check out this example which "logs" an embed to the logChannel.

Discord.js Filter Discord Events From Only 1 Server

I am working on trying to filter events for only 1 server rather than all servers the bot is in, but I'm trying to figure out how to exactly save each guild the bot is in as an collection so I can just filter events based on a guild ID I desire. Is this even possible? This is a snippet of the code I have to date, it's able to display the server names and ID's the bot is currently in, the events are working properly but triggering for all servers rather than the one I desire, how would I go about filtering for one guild collection?
const Discord = require('discord.js')
const bot = new Discord.Client()
const config = require('./config.json')
bot.on('ready', () => {
console.log(`Logged in as ${bot.user.tag}!`);
//Sets Activity
//client.user.setStatus('invisible')
bot.user.setActivity("Discord Cooks", { type: "WATCHING"})
console.log("Set User Activity!");
//Online Webhook
const webhookClient = new Discord.WebhookClient('','');
const embed = new Discord.MessageEmbed()
.setTitle(`${bot.user.tag} is online`)
.setColor('#FFFF00')
.setTimestamp()
webhookClient.send(embed);
bot.guilds.cache.forEach((guild) => {
console.log(guild.name, guild.id);
});
});
bot.on("channelCreate", (channel) => {
console.log(`channelCreate: ID: ${channel.id} Name: ${channel.name}`);
});
bot.on("channelUpdate", (oldChannel, newChannel) => {
console.log(`channelUpdate -> ${oldChannel.name} to ${newChannel.name}`);
});
bot.on("channelDelete", (channel) => {
console.log(`channelDelete: ID: ${channel.id} Name: ${channel.name}`);
});
bot.login(config.bottoken)
You can only execute code if event happened on exact server in much easier way:
if(guild.id == "GUILD_ID") {
// code
}
Also as #MrMythical said, you can just use if (message.guild.id !== "GUILD_ID") return; if you only need to run your code for 1 guild!

Guild Members TImeout: Members didn't arrive in time

So I have this command that shows the riches users in a server this command worked yesterday however recently it has stopped working.
const { MessageEmbed } = require("discord.js");
const { stripIndents } = require("common-tags");
const { prefix } = require("../../botconfig.json");
const db = require('quick.db')
let bal = require('../../database/balance');
let rep = require('../../database/rep');
let work = require('../../database/works');
module.exports = {
config:{
name: "rich",
aliases: ["r"],
category: "currency",
description: "Tells who is rich",
usage: ""
},
run: async (client, message, args) => {
// Get all members of the server before doing anything
message.guild.members.fetch().then(guildMembers => {
let board = [];
for (let key of Object.keys(bal)) {
// Checks if the collection of GuildMembers contains the key.
if (guildMembers.has(key)) {
let value = Object.assign({user: guildMembers.get(key).user}, bal[key]);
board.push(value);
}
}
const emojis = [':first_place:', ':second_place:', ':third_place:', ':small_blue_diamond:', ':small_blue_diamond:']
board = board.sort((a,b) => b.balance-a.balance).splice(0, 5);
let top = board.map((x, i) => `${emojis[i]} **${x.balance.toLocaleString()}** - ${x.user.tag}`).join('\n');
let embed = new MessageEmbed()
.setColor("RANDOM")
.addField(`Richest users in **${message.guild.name}**`, `${top}`)
.setFooter('Switch Version 1.1');
return message.channel.send(embed);
}).catch(console.error)
}
}
The error code when the !rich command is used is as follows:
Guild_Members_Timeout: Members didn't arrive in time
I don't know if this is an issue within the bot or if it is an issue with discord.
Okay I have found the answer to my own problem it seems I needed to add intents to my discord bot to fetch the members.
All I did was add this line of code and it worked.
const intents = new Intents([
Intents.NON_PRIVILEGED, // include all non-privileged intents, would be better to specify which ones you actually need
"GUILD_MEMBERS", // lets you request guild members (i.e. fixes the issue)
]);
const client = new Client({ ws: { intents } });
None of my discord.js guildmember events are emitting, my user caches are basically empty, and my functions are timing out? . In this post it is explained in great detail and that helped me out a lot.TLDR:go to discord developer portal on your particular application ,go to bot , on bot permissions tick whatever is needed and copy the number.Then use this number as a constructor parameter for new Discord.Intents('insert the number here').This worked for me.

How to Edit Embedded Message on Discord When Role Has Been Assigned or Removed

I am working on a Discord bot and I have an embed that shows the names of people who has that role, I want to make it edit that one message everytime the role is assigned or removed. Help would be very appreciated 🙂
You can use the Client#guildMemberUpdate. The event is fired whenever the GuildMember is updated. (This includes: role added, role removed, nickname changes etc.)
Here's a simple example:
client.on("guildMemberUpdate", (oldGuildMember, newGuildMember) => {
if (oldGuildMember.guild.id == "GuildID") { // Checking if the event was fired within the required Guild.
if (!oldGuildMember.roles.cache.equals(newGuildMember.roles.cache)) { // Checking if the roles were changed.
const Channel = client.channels.cache.get("ChannelIUD"); // Getting the channel your MessageEmbed is in.
const Role = oldGuildMember.guild.roles.cache.get("RoleID"); // Getting the Role by ID.
if (!Role || !Channel) return console.error("Invalid role or channel.");
Channel.messages.fetch("MessageID").then(message => { // Getting the MessageEmbed as a Message by ID
const Embed = new Discord.MessageEmbed(); // Updating the MessageEmbed.
Embed.addField(`Members of ${Role.name}`, Role.members.size > 0 ? `${Role.members.map(member => member.user.tag).join("; \n")};` : "This role has no members.");
Embed.setColor("RED");
message.edit(Embed).catch(error => console.error("Couldn't edit the message."));
}).catch(error => console.error("Couldn't fetch the message."));
};
};
});

How can I send private message to a new user who joined my server?

I want the person who enters the server will receive from the message. I tried to do something like that, but it did not work:
bot.on('guildMemberAdd', member => {
var joiner = member.user.username;
const embeddd = new Discord.RichEmbed()
.setColor('#ff0000')
.setTitle(`Hi, ${joiner}.`)
message.author.send(embeddd);
})
message.author.send(embeddd);
There is no message parameter in a client's guildMemberAdd event. If you want to send your embed to the member that joined, use the member parameter you already have.
bot.on('guildMemberAdd', member => {
var embed = new Discord.RichEmbed()
.setColor('#ffffff')
.setTitle('**Hello!**')
.setDescription(`Welcome to ${member.guild}.`)
.setFooter(member.guild.name, member.guild.iconURL);
member.send(embed)
.catch(console.error);
});
See GuildMember.send().

Resources