How do I edit a message from a different channel that my bot sent? - discord.js

I'm making a suggestion module on my bot, and I have everything else down, but am struggling on fetching the message the bot sent and editing it using a command that was sent in a different channel.
I tried doing await message.guild.channels.cache.get("channel-id-here").messages.fetch("the-actual-messages-id-here").edit({ content: 'Test' }) but it didn't work.

Your code, while in theory, should work, most likely doesnt due to unresolved promises.
In the line
await message.guild.channels.cache.get("channel-id-here").messages.fetch("the-actual-messages-id-here").edit({ content: 'Test' })
The await at the beginning is trying to resolve the promise of the edit method, where there is another promise to be resolved at the <MessagesManager>#fetch method. In other words you're ignoring the promise returned from the fetch which will resolve no messages. Consider the following change:
const messages = await message.guild.channels.cache.get("channel-id-here").messages;
await messages.fetch("the-actual-messages-id-here").edit({ content: 'Test' });
Or if you really want a one-liner (I dont suggest this as it compromises on readability) you could use:
await (await message.guild.channels.cache.get("channel-id-here").messages.fetch("the-actual-messages-id-here")).edit({ content: 'Test'

Related

.awaitMessageComponent() in an ephemeral reply and then editing it

I have been trying to implement an interaction collector as per the discord.js guide, but the guide does not explain much of anything and the pieces I have puzzled together from other sources do not fit together. Here's the example from the guide:
message.awaitMessageComponent({ filter, componentType: 'SELECT_MENU', time: 60000 })
.then(interaction => interaction.editReply(`You selected ${interaction.values.join(', ')}!`))
.catch(err => console.log(`No interactions were collected.`));
It took me a day to figure out that you can define a message object like so:
message = await interaction.channel.send(content: 'text', components: >select menu<)
That works to run .awaitMessageComponent() and to grab the input from the select menu, however interaction.editReply() gives an error: INTERACTION_NOT_REPLIED
Moreover, I need it to be a reply anyway, however
message = await interaction.reply(content: 'text', components: >select menu<)
leaves message as undefined, so of course I cannot run .awaitMessageComponent() on it.
So I do not understand what I am supposed to do to do what that guide is doing.
I would very much appreciate any insight into this issue.
Unfortunately all other guides (usually on collectors) also start with a .send() message and most other resources go way over my head, as I have no real background in coding/scripting.
EDIT:
As Malik Lahlou points out, you can assign the reply by including the fetchReply:option, like so:
message = await interaction.reply({ components: [select menu], fetchReply: true })
However that still does not allow the guide's code to run (error INTERACTION_NOT_REPLIED, so after some more research I finally found a way to use .awaitMessageComponent() and applied to the guide's example it would look like this:
await interaction.reply({ components: [select menu], ephemeral: true });
const collectedSelect = await interaction.awaitMessageComponent({ filter, componentType: 'SELECT_MENU', time: 60000 })
.then(interaction => interaction.editReply(`You selected ${interaction.values.join(', ')}!`))
.catch(err => console.log(`No interactions were collected.`));
Simple answer, add the fetchReply option when replying to the interaction :
const message = await interaction.reply({
// content : ...,
// components : ...,
fetchReply: true
})
Another way would be to use interaction.fetchReply after awaiting the reply but it's better to directly give it as a parameter so discord.js does this stuff for us :D Here's an example on the official discord.js guide

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')

Discord JS v12: How do you get a message's content by it's ID?

I'm relatively new to discord.js, and I've started building a bot project that allows a user to create a message via command, have that message stored in a hidden channel on my private server, and then said message can be extracted through the message ID.
I have the write working and it returns the message ID of the message sent in the hidden channel, but I'm completely stumped on the get command. I've tried searching around online but every method I tried would return errors like "Cannot read property 'fetch' of undefined" or "'channel' is not defined". Here are some examples of what I tried, any help would be appreciated. Note that my args is already accurate, and "args[0]" is the first argument after the command. "COMMAND_CHANNEL" is the channel where the command is being executed while "MESSAGE_DATABASE" is the channel where the targeted message is stored.
let msgValue = channel.messages.cache.get(args[0])
client.channels.cache.get(COMMAND_CHANNEL).send(msgValue.content)
let msgValue = msg.channel.message.fetch(args[0])
.then(message => client.channels.cache.get(COMMAND_CHANNEL).send(msgValue.content))
.catch(console.error);
I even tried using node-fetch to call the discord API itself
const api = require("node-fetch")
let msgValue = api(`https://discordapp.com/api/v8/channels/${MESSAGE_DATABASE}/messages/${args[0]}`)
.then(message => client.channels.cache.get(COMMAND_CHANNEL).send(msgValue.content))
.catch(console.error);
Am I missing something or am I making some sort of mistake?
Edit: Thanks for the help! I finished my bot, it's just a little experimental bot that allows you to create secret messages that can only be viewed through their ID upon executing the command :get_secret_message <message_id>. I posted it on top.gg but it hasn't been approved yet, so in the meantime if anyone wants to mess around with it here is the link: https://discord.com/api/oauth2/authorize?client_id=800368784484466698&permissions=76800&scope=bot
List of commands:
:write_secret_message - Write a secret message, upon execution the bot will DM you the message ID.
:get_secret_message <message_id> - Get a secret message by its ID, upon execution the bot will DM you the message content.
:invite - Get the bot invite link.
NOTE: Your DMs must be turned on or the bot won't be able to DM any of the info.
My test message ID: 800372849155637290
fetch returns the result as promise so you need to use the then to access that value instead of assigning it to a variable (msgValue). Also you made a typo (channel.message -> channel.messages).
I would recommend using something like this:
msg.channel.messages
.fetch(args[0])
.then(message => {
client.channels
.fetch(COMMAND_CHANNEL)
.then(channel => channel.send(message.content))
.catch(console.error)
})
.catch(console.error)
I think you were quite close with the second attempt you posted, but you made one typo and the way you store the fetched message is off.
The typo is you wrote msg.channel.message.fetch(args[0]) but it should be msg.channel.messages.fetch(args[0]) (the typo being the missing s after message). See the messages property of a TextChannel.
Secondly, but this is only a guess really as I can't be sure since you didn't provide much of your code, when you try to fetch the message, you are doing so from the wrong channel. You are trying to fetch the message with a given ID from in the channel the command was executed from (the msg.channel). Unless this command was executed from the "MESSAGE_DATABASE" channel, you would need to fetch the message by ID from the "MESSAGE_DATABASE" channel instead of the msg.channel.
Thirdly, if you fetch a message, the response from the Promise can be used in the .then method. You tried to assign the response to a variable msgValue with let msgValue = msg.channel.message.fetch(args[0]) but that won't do what you'll expect it to do. This will actual assign the entire Promise to the variable. What I think you want to do is just use the respone from the Promise directly in the .then method.
So taking all that, please look at the snippet of code below, with inspiration taken from the MessageManager .fetch examples. Give it a try and see if it works.
// We no longer need to store the value of the fetch in a variable since that won't work as you expect it would.
// Also we're now fetching the message from the MESSAGE_DATABASE channel.
client.channels.cache.get(MESSAGE_DATABASE).fetch(args[0])
// The fetched message will be given as a parameter to the .then method.
.then(fetchedMessage => client.channels.cache.get(COMMAND_CHANNEL).send(fetchedMessage.content))
.catch(console.error);

discord.py get webhooks of channel

I'm trying to make a webhook so if anyone says 'ez' it deletes it and sends a message with the webhook with a random message. Originally what I was doing was
if "ez" in message.content:
webhook = await message.create_webhook(name=ctx.author.name)
await webhook.send(ezmessages[random.randint(0, len(ezmessages))-1], username=message.author.name, avatar_url=message.author.avatar_url)
await message.delete()
await webhook.delete()
but the problem is this gets rate limited if webhooks are created and deleted too quickly. So instead what I want to do is check if the bot already has a webhook for the text channel, and if there is one use that but if not use a different one. I thought this would work:
for webhook in message.channel.webhooks:
await webhook.send(ezmessages[random.randint(0, len(ezmessages))-1], username=message.author.name, avatar_url=message.author.avatar_url)
but I get the error
TypeError: 'method' object is not iterable
Even though it should return a list
Anyone know how to correctly iterate over this?
TextChannel.webhooks it's not an attribute, its a function and a coroutine, so you need to call it and await it
webhooks = await message.channel.webhooks()
for webhook in webhooks:
...
docs

React component only displays status code error message instead of custom ones

During POST to register new user I check if that user already exists in mongoDB data base and if yes display this in react near the register form. I'm using express.js to create my API and axios to send requests from client side. This is how I check if user is registered.
const user = await Model.User.findOne({email: req.body.email});
if(user) return res.status(400).send('User already registered');
This is the function that is being called on Register button click:
handleSubmit= async (userData) =>{
await apis.registerNewUser(userData)
.then(res => console.log(res.body))
.catch(err => {
console.log(err);
this.setState({errorMessage: err.message});
})
}
The problem is that I can't display the custom error message that I add when sending response. Instead of getting "User already registered" I get "400 Bad request" showing near my register form. When I post through postman there is no problem, the response "User already registered" shows up in the response text window however that part doesnt exist when recieving error on react side. I can't send user an error that tells him nothing about the reason why he can't register. How can I get "User already registered" in react?
I have found the solution. In order to read the property of that custom text put inside send() when catching error I need to read from err.response.data - that's the right property to read "User already registered".I hope it helps someone one day.

Resources