How to log custom status updates using discord.js? - discord.js

I've been working on a blacklisted words option, along with logging when a member of a guild sets a custom status containing a blacklisted word. However, I've run into a problem that I sometimes get the old status same as the new status (only for some guilds tho, others are fine). My code it here:
client.on("presenceUpdate", (oldPresence, newPresence) => {
const newCustomStatus = newPresence.activities[0].state
const oldCustomStatus = oldPresence.activities[0].state
console.log('old status: ' + oldCustomStatus)
console.log('new status: ' + newCustomStatus)
})
oldCustomStatus is sometimes same as newCustomStatus in some guilds, which makes it impossible to log the old status. It only happens in like a half of the guilds the member and bot share.
I thought about making a cache of all statuses on bots start and only toggling the event once, which would allow me to read both the new and old status, since there was always at least one guild with correct info. However, I couldn't then run a per-guild check for blacklisted words, since I don't know a way of reading guild IDs from a user object.
Any way of fixing the broken old and new status? Or a way to get a list of guild IDs the user and bot share?
Thanks

I found out it fires more than once by also logging the guild ID. That seems to solve half of the issue since the next fire takes the new status as both the old and new status. Not sure why it fires more than once tho.A simple solution for the logger is to use an if statement and compare the new and old statuses, and only log them if they are different:
client.on("presenceUpdate", (oldPresence, newPresence) => {
const newCustomStatus = newPresence.activities[0].state
const oldCustomStatus = oldPresence.activities[0].state
if(newCustomStatus != oldCustomStatus) {
console.log('old status: ' + oldCustomStatus)
console.log('new status: ' + newCustomStatus)
}
})
Not sure why it fires more than once, this solution is 100% working for me tho.

Related

How do I fetch all reactions from a specific message? [Discord.js]

So, I want to make a command for my bot which can fetch all reactions from a given message ID and store these three categories into arrays, for each reaction:
the name of the reaction (eg. :smile:)
the users who reacted (eg. RandomUser#4654, ILikePotatoes#1639)
and how many people reacted with this emoji (eg. Count: 2)
I've tried using the ReactionCollector, but it doesn't work for reactions added prior to the event being called. I've also tried using an external module called discord-fetch-all but all it does is either sending Promise { <Pending> } or undefined when I use .then().
PS: I've already set up a command handler that takes a message ID for argument.
Thank you in advance for helping.
You can get the specific message you want to be check for reactions by using:
const messageReacted = client.channels.cache.get('channelId').messages.fetch('messageId')
Then, you can go through each reaction in the message's cached reactions by using forEach
Then, in the .forEach, you can get the emoji name by using reaction._emoji.name, the number of users who used this reaction by reaction.count and all the users who reacted on the message by fetching them: await reaction.users.fetch().
Your final code might look something like:
const messageReacted = await client.channels.cache
.get('channelId')
.messages.fetch("messageId");
messageReacted.reactions.cache.forEach(async(reaction) => {
const emojiName = reaction._emoji.name
const emojiCount = reaction.count
const reactionUsers = await reaction.users.fetch();
});

Message object .edit() stops working after some time

First I create an object
var queue = {1:{},2:{},3:{}};
And then I store the message based on QueueKey, or edit if it's already created
if (typeof queue[QueueKey].messageOBJ == 'undefined')
{
queue[QueueKey].messageOBJ = await configChannel.send({ embeds: [getEmbedFloor(QueueKey)] });
}
else
{
queue[QueueKey].messageOBJ = await queue[QueueKey].messageOBJ.edit({ embeds: [getEmbedFloor(QueueKey)] });
}
everything starts working well but after sometime(1~2 hours) bot stops editing the already created message, looks like it lose object reference.
It not pops any error message or code break, seems like the message was edited sucessfully but the real message in discord still the same
I'm thinking in store the messageID instead the whole object and search for the message ID with .fetch() but this will lead to other problems
is there any way to store message Objects properly?
I discovered my problem, actually bot was editing the message to frequently, so after some time discord "auto ban" my bot for some time, something like a cooldown, só it starts to get slower and slower, up to seems like it is stuck.
My solution was check message before edit, to compare if the changes in message are really necessary, before edit or not

I want a discord bot send a dm to somebody by their id

if (message.content === "!test"){
client.users.cache.get('id').send('message');
console.log("message sent")
}
This method doesn't work and I wasn't able to find any other methods that worked
Is there a spelling mistake or this method is outdated?
I've actually encountered this error myself once. There are two problems you might be facing here:
The user isn't cached by discord.js yet
There isn't a DMChannel open for that user yet
To solve the first one, you have to fetch the user before doing anything with it. Remember this is a Promise, so you'll have to either await for it to complete or use .then(...).
const user = await client.users.fetch('id')
Once you've fetched your user by their ID, you can then create a DMChannel which, again, returns a promise.
const dmChannel = await user.createDM()
You can then use your channel like you normally would
dmChannel.send('Hello!')
Try to create a variable like this:
var user = client.users.cache.find(user => user.id === 'USER-ID')
And then do this:
user.send('your message')

How to not send bots message edit discord.js

I have a message edit log but I want to stop sending the log if a mobs message was updated, I tried a few codes like
if(bot.oldMessage.content.edit()){
return;
}
It showed and error
cannot read property 'edit' of undefined
I then removed edit then content was undefined. The code for the message update is below.
The Code
module.exports = async (bot, oldMessage, newMessage) => {
let channels = JSON.parse(
fs.readFileSync('././database/messageChannel.json', 'utf8')
);
let channelId = channels[oldMessage.guild.id].channel;
let msgChannel = bot.channels.cache.get(channelId);
if (!msgChannel) {
return console.log(`No message channel found with ID ${channelId}`);
}
if (oldMessage.content === newMessage.content){
return;
}
let mEmbed = new MessageEmbed()
.setAuthor(oldMessage.author.tag, oldMessage.author.displayAvatarURL({dynamic: true}))
.setColor(cyan)
.setDescription(`**Message Editied in <#${oldMessage.channel.id}>**`)
.addField(`Before`, `${oldMessage.content}`)
.addField(`After`, `${newMessage.content}`)
.setFooter(`UserID: ${oldMessage.author.id}`)
.setTimestamp()
msgChannel.send(mEmbed)
}
How would I stop it from sending the embed if a bots message was updated.
Making a really simple check will resolve this issue. In Discord.js there is a user field that tells you if the user is a bot or not.
In fact, it is really recommended you add this in the "onMessage" part of your code as it stops other bots from using your bot, this is to make sure things are safe and no loopbacks/feedbacks happen, either way, you don't want a malicious bot taking advantage of your bot, which can get your bot in trouble too.
Here is what you want to do;
if (message.author.bot) return;
What this code specifically does is check if the message's author is a bot, if it returns true, it will break the code from running, if it returns a false, the code continues running.
You can do the same if you want to listen to bots ONLY by simply adding a exclamation mark before the message.author.bot like this;
if (!message.author.bot) return;
It is also possible to see what other kinds of information something holds, you can print anything to your console. For example, if you want to view what a message object contains, you can print it into your console with;
console.log(message) // This will show everything within that object.
console.log(message.author) // This will show everything within the author object (like ID's, name, discriminators, avatars, etc.)
Go ahead and explore what you can do!
Happy developing! ^ -^
That is really easy to do. All you need to do is check if the author of the message ist a bot and then return if true. You do that like this
if (oldMessage.author.bot) return;

Discord.js - Getting information after Prefix and command

I'm now working in a new command, a poll command.
For that, I need a way of get the arguments after the prefix and the command itself.
Example: +Poll Do you like puppies?
And, it'd ignore the "+Poll", and get only the question itself, for then create a poll.
To get the arguments, I'm using:
var Args = message.content.split(/\s+/g)
You probably want to try creating the poll with a command, store the question in your database, and then use a separate command to display current polls that are open. Then the users would select the poll via command and the bot would await the response to the question.
I won't go into detail about storing the question in a database, because that's a totally different question. If you need help setting up a local database and store the polls, link to another question and I'll be happy to give more examples.
To go with your question, I would suggest using subStr to save each word after the command in an array, so you can later use those parts in the code. Something like this will store everything after !poll in the variable poll:
if (message.content.startsWith("!poll ")) {
var poll = message.content.substr("!poll ".length);
// Do something with poll variable //
message.channel.send('Your poll question is: ' + poll);
});
For the user answering the poll, you can try using awaitMessage to ask the question, and give a set number of responses. You would want to wrap this in a command that queries your database for the available polls first, and use that identifier to actually get the right question and possible reponses. The example below just echos the response that is collected, but you would want to store the response in the database instead of sending it in a message.
if (message.content === '!poll') {
message.channel.send(`please say yes or no`).then(() => {
message.channel.awaitMessages(response => response.content === `yes` || response.content === 'no', {
max: 1, // number of responses to collect
time: 10000, //time that bot waits for answer in ms
errors: ['time'],
})
.then((collected) => {
var pollRes = collected.first().content; //this is the first response collected
message.channel.send('You said ' + pollRes);
// Do something else here (save response in database)
})
.catch(() => { // if no message is collected
message.channel.send('I didnt catch that, Try again.');
});
});
};

Resources