What does Message.fetch() actually do in discord.js - javascript

According to the Message#fetch() docs, this function simply fetches the message it was called on. However, I'm not sure in which circumstance it would ever make sense to use this function.
According to the screenshot above, this method returns Promise<Message>. I'm confused, because why would you need to fetch a message you already have access to? For example:
// let's say somebody sent the message `hello`
client.on('message', (message) => {
console.log(message.content) // this would return `hello`
message.fetch((message) => console.log(message.content)) // this would also return `hello`; it's the same object
So, what's the point of it? If you didn't have access to the message, you wouldn't be able to use Message.fetch() anyways.
And I'd ask the same question for Channel#fetch, ClientUser#fetch, Guild#fetch, GuildMember#fetch, GuildPreview#fetch, etc.

If we dive into the source of the Message class and look for the fetch method, we see something like this:
/**
* Fetch this message.
* #param {boolean} [force=false] Whether to skip the cache check and request the API
* #returns {Promise<Message>}
*/
fetch(force = false) {
return this.channel.messages.fetch(this.id, true, force);
}
The fetch() method in this cases, retreives the last message posted in the channel. If you invoke this method and log the output, you see that it fetches the message you have posted. It simply returns asynchronous message object. Promise<Message>.
So let's say you post this message Hello, i'm a message. and invoke and log the .fetch() method, you see in the console the message object and content Hello, i'm a message.. All this does is fetching the message posted in the channel. Same goes for channel#fetch, ClientUser#fetch.
All it does is using the cache to fetch a channel, user, guild, message. The force argument is to receive the realtime data.
The force flag is used if you want to skip the cached message and want to do the API request.
If you wish to fetch all messages or a few messages, you can use the MessageManager class:
message.channel.messages.fetch('Message ID');
or
message.channel.messages.fetch({
limit: 5, // Amount of messages to be fetched in the channel
before: "Snowflake (ID from message to be fetched)",
after: "Snowflake (ID from message to be fetched)",
});
More on this: https://discord.js.org/#/docs/main/stable/typedef/ChannelLogsQueryOptions

The point of this fetch command is because there are many situations where your bot does not have messages in cache to access. The most basic example is 1. During development you are are editing code and restarting the bot. Now those messages are lost and the bot doesn't have full access to them.
Your running program loses internet connection - enjoy your limited access and errors.
Cached messages are limited to 100 / channel. If you want access to earlier messages you must fetch. A common example is when the bot is asked to delete messages from a channel.
In our some of our servers the messages can exceed the cache amount within a minute. Specific messages / commands need to be fetched to auto-delete after x minutes.

Related

messageDelete event and partials discord.js v12

Lets say that I have a messageDelete event that I want to get the data from. Since I am required to have the Channel and Message partials for the messageDelete event to fire, the message object returned in the messageDelete event will be partial.
When I'm trying to fetch this message, it returns an error saying that the fetched message is unkown.
So how can I get information like the content etc. from the deleted message?
My current code:
client.on("messageDelete", async message => {
if (message.partial) await message.fetch() // this is where the error occurs
console.log(message.content) // will only work on non partial messages
})
Is there any way around this, cause it would be useful to get the information from past deleted messages.
EDIT
Toasty recommended that I use the audit logs, to which I have used the following code
client.on("messageDelete", async message => {
console.log(message) // seeing whats avaliable in the return
if (message.partial) console.log("message was partial") // checking if the message was partial to compare with non partial messages
if (message.guild) {
const fLogs = await message.guild.fetchAuditLogs({limit:1, type:"MESSAGE_DELETE"}) //getting audit logs
const log = fLogs.entries.first()
let {executor, target} = log
console.log("Message deleted by "+executor.tag+" in "+target) // responding.
}
})
Output:
message was partial
Message deleted by CT-1409 "Echo"#0093 in 606323576714559489
So I can get the who and the (sort of) what of the message that was deleted.
I still cannot get the rest of the message information, as if I tried to fetch the message with the target id, it would give me Unkown Message again. But also when I logged the message object to start with, I noticed that there was a decent amount of information already present, which may mean some data would still be accessible from a partial message. I don't know how much, but perhaps enough for what I need.
That you can't get any information of the deleted message is probably because the message..has been deleted.
As you can read here, this is not possible and would also be a violation of the rules and a violation of the privacy of users.
But...
...if you have a command for deleting messages, you could get the information of the message before you delete it and do stuff with it
Alternatively, you could work with the audit logs

Get information about the mentioned user / message author with discord.js

**• Server Roles:** <#&${user._roles.join('> <#&')}>,
^^ Cannot read property 'join' of undefined
I used message.member._roles.join('> <#&')}>`,
But it always showed the roles of the user that wrote the command, and not the user that you mentioned.
Message.member is user who sent this message.
If you want to get mentioned guild members you need to use message.mentions.members
which returns an collection of mentioned users.
Your code should look like:
// To make sure that only one member is mentioned
if(message.mentions.members.size == 1){
const roles = `<#&${message.mentions.members.first()._roles.join('> <#&')}>`
message.channel.send(roles);
}
I recommend sending empty message first and then editing its content to add these mentions just to avoid pinging whole server.

Cannot access session state data on another function

I'm creating an inactivity check for my bot where it sends a message to the user if X amount of minutes have passed since the last message he sent.
bot.dialog('SomeDialog',
function(session, args){
let text = "The text sent to the user";
session.send(text, session.message.text);
check(session); //The function where I send the session to do the checking
session.endDialog();
}
);
The check function is where the problem happens:
check(session){
if(!session.conversationData.talked){
session.conversationData.talked = 1;
}
}
When I run it, I always get
Cannot read property 'conversationData' of undefined
If I use session.conversationData.talked within the bot.dialog it works, but not on the check function.
What am I doing wrong here?
Your code snippet works fine on my side, maybe you can provide your whole picture of your porject for further analysis.
However, to your requirememnt, you can consider to use the node package botbuilder-timeout,
This could be an "async" timing issue. The session on your browser / server needs to be sync'd.
Is this JS server side, or browser side? And what framework is this intended for?

Twilio Nodejs - How to place call to twilio and gather entered digits to call another person

I'm trying to figure out how to create calls from my Twilio number after I've dialed into it and entered a number. After reading the docs I see that this is done with the gather feature, which can then be redirected to another Twiml document to handle the response. However, I can't quite get it to work. I'm extremely confused on how to execute Twiml correctly and how to access the request parameters in another Twiml doc. I've also looked into Twimlets but I wasn't able to construct what I needed there correctly either.
I've gone back and tried to just make a simple voice message play when only my number calls. If it's not me calling then it needs to be redirected to a Twiml url which will try to connect to my phone. If that fails it will prompt the caller to leave a message.
//Handle incoming call requests
app.post('/call', function(req, res) {
var twiml = new twilio.TwimlResponse();
res.type('text/xml');
if ( req.body.From === "+1555555555") {
twiml.say('Hello', {voice: alice});
res.send(twiml.toString());
} else {
// Do something here.
}
});
I've found the correct solution for my problem. I wasn't initiating the twilio.TwimlResponse() correctly.
In order to solve this issue, I needed to use == instead of === so that my req.body.from value wouldn't get coerced.

How do you link GCM chrome push notifications and payload data?

Push notifications in Chrome via GCM are driving me crazy.
I've got everything up and running. I serve the push using my python server to GCM. A service worker displays the push notification fine.
To my knowledge, there is NO data passed with push events. Sounds like it's coming soon but not available yet.
So just before the push notification shows, I call my server to get extra data for the push notification. But I have no information on the push notification to send to my server to match and return relevant data.
Everything I can think of to match a notification and user data is purely speculative. The closest thing I can find is a timestamp object on the PushEvent{} that roughly matches the successful return of the GCM call for each user.
So how are other people handling custom payload data to display Chrome push notifications?
The PushEvent{} does not seem to have any ID associated with it. I know the user that the push is for because I've previously stored that information at the time of registration.
But once I receive a push, I have no idea of knowing what the push was for.
I would like to avoid:
Trying to match based on timestamp (since notifications displays are not guaranteed to be instant).
Trying to pull the 'latest' data for a user because in my case, there could be several notifications that are sent for different bits of data around the same time.
How are other sites like Whatsapp and Facebook linking custom payload data with a seemingly sterile event data as a result of a push notification?
How are you doing it? Any suggestions?
Here's what my receiver code looks like:
self.addEventListener('push', function(event) {
event.waitUntil(
fetch("https://oapi.co/o?f=getExtraPushData&uid=" + self.userID + "&t=" + self.userToken).then(function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' + response.status);
throw new Error();
}
return response.json().then(function(data) {
if (data.error || !data.notification) {
console.error('The API returned an error.', data.error);
throw new Error();
}
var title = data.notification.title;
var message = data.notification.message;
var icon = data.notification.icon;
return self.registration.showNotification(title, {
body: message,
icon: icon,
});
});
}).catch(function(err) {
console.error('Unable to retrieve data', err);
var title = 'An error occurred';
var message = 'We were unable to get the information for this push message';
var icon = "https://oapi.co/occurrences_secure/img/stepNotify_1.png";
var notificationTag = 'notification-error';
return self.registration.showNotification(title, {
body: message,
icon: icon,
tag: notificationTag
});
})
);
});
I understand your problem, and i've been fiddling with the same when i wanted to use chrome notification. You can use indexedDB to save ObjectStore and retrieve data in webServices.
IndexedDB is accessible to webservices. I am using it to store user information and when the user recieves a push notification i pass the stored access key to identify the user and pass him relevent information.
Here's matt gaunt's tutorial which says indexed db is accessible to web services:
http://www.html5rocks.com/en/tutorials/service-worker/introduction/
Here's a good indexedDB tutorial:
http://blog.vanamco.com/indexeddb-fundamentals-plus-a-indexeddb-example-tutorial/
Assuming you are still in the past. That is, sending only a push trigger to your browser with no payload it's now time to move on with time. You can now send payload in your push events. Since you seem familiar with GCM, it's ok to go with that though there is now the Web Push Protocol which is browser vendor independent.
Briefly, to make that work you need to encrypt your payload with specifications found here, in your server.
There is a node by google chrome and PHP implementations for that, that I know of.
You may check out the PHP Web Push here.
In the browser you would need to provide the subscription object now with the p256dh and auth on top of the endpoint as before.
You may check this out for more details.

Categories

Resources