I don't want bots to join my server and advertise in chat or dm's of users, so I thought I'll let new users react to a message, and after that my bot will send them a question in dm's, if they answer correctly he should give them the verified role. The bot can send the message, but after that an error appears.
(node:12356) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'type' of undefined
I dont know how to solve this, because in the Docs channel.type exists.
Here is the code
client.on('messageReactionAdd', async (reaction, user) =>{
const filter = m => true
if (reaction.message.partials) await reaction.message.fetch();
if (reaction.partials) await reaction.fetch();
if (user.bot) return;
if (!reaction.message.guild) return;
if (reaction.message.id === '814035246399488001'){
if (reaction.emoji.name === 'β
'){
user.send("What is the subtrahend of 156 - 123?")
.catch(()=>{console.log('couldnt send a DM')})
if ( channel.type === 'dm' )
user.dmChannel.awaitMessages(filter, {
max:1,
time:30000,
error:["time"]
})
.then(collected => {
if (collected.first().content === "33"){
reaction.message.guild.members.cache.get(user.id).roles.add('779523805492019254')
if(err => {
console.log(err)
});
}else{
user.send("this is not the correct answer, you will not get verified.")
return;
}
})
}
}
});
I have asked around in some discord servers and found the solution:
if (reaction.emoji.name === 'β
'){
let msg = await user.send("What is the subtrahend of 156 - 123?")
.catch(()=>{console.log('couldnt send a DM')})
if (msg.channel.type == `dm`)
What i think happens is, the bot now knows that msg.channel.type is the channel where he sent the message before, and yeah, i am so happy now that it works :3 and thank you too NullDev your comment lead to the solution too <3
Related
So, I need a way to forward a message sent in the bot's dm to a specific channel in my server.
this is the code that I got so far:
execute(message, args) {
if(message.channel.type == "dm"){
let cf = args.join(' ')
const cfAdm = message.guild.channels.cache.get('767082831205367809')
let embed = new discord.MessageEmbed()
.setTitle('**CONFISSΓO**')
.setDescription(cf)
.setColor('#000000')
const filter = (reaction, user) => ['π', 'π'].includes(reaction.emoji.name);
const reactOptions = {maxEmojis: 1};
cfAdm.send(embed)
.then(function (message) {
message.react('π')
.then(() => message.react('π'))
/**** start collecting reacts ****/
.then(() => message.awaitReactions(filter, reactOptions))
/**** collection finished! ****/
.then(collected => {
if (collected.first().emoji.name === 'π') {
const cfGnr = message.guild.channels.cache.get('766763882097672263')
cfGnr.send(embed)
}
})
});
}
else {
message.delete()
message.channel.send('Send me this in the dm so you can stay anon')
.then (message =>{
message.delete({timeout: 5000})
})
}
}
But for some reason that I can't seem to understand, it gives me this error:
TypeError: Cannot read property 'channels' of null
If anyone can help me, that would be greatly apreciated.
Thanks in advance and sorry for the bad english
The error here is that you are trying to call const cfAdm = message.guild.channels.cache.get('ID') on a message object from a Direct Message channel ( if(message.channel.type == "dm"){)
DMs don't have guilds, therefore message.guild is null and message.guild.channels does not exist.
You will need to first access the channel some other way. Luckily, Discord.js has a way to access all channels the bot can work with* (you don't need to muck around with guilds because all channels have unique IDs):
client.channels.fetch(ID) or client.channels.cache.get(ID)
(I have not tested this but it seems fairly straight forward)
*See the link for caveats that apply to bots in a large amount of servers.
I'm trying do create a bot that can add specific role to the user who react to the message with the emoji listed.
With the code below, I can check who reacted to the message and i can also check what emoji they react with, but when I am trying to add role to them, error pops up say user.addRole is not a function is there any way to solve this problem? Thanks a lot!
Code that create an embed message for user to react
let args = message.content.substring(PREFIX.length).split(" ");
if(message.content.toLowerCase() === '?roles' && message.author.id === 'adminId' && message.channel.id === 'channel id'){
const role = new Discord.MessageEmbed()
.setTitle("ROLES")
.setColor('#6a0dad')
.setDescription('π₯ - ROLE1\nβοΈ - ROLE2\nπ§ - ROLE3')
message.channel.send(role).then(re => {re.react('π₯'),re.react('βοΈ'),re.react('π§')});
message.awaitReactions().then(collected=>{
const reaction = collected.first();
})
}
Code that get the react user and trying to add role
const bot = new Discord.Client({ partials: ['MESSAGE', 'CHANNEL', 'REACTION'] });
bot.on('messageReactionAdd', async (reaction, user) => {
if (reaction.partial) {
try {
await reaction.fetch();
} catch (error) {
console.log('Something went wrong when fetching the message: ', error);
return;
}
}
if(reaction.message.id === 'id of that embed message sent'){
if(reaction.emoji.name === "π₯"){
//console.log('ROLE1');
user.addRole('id of role 1');
}
if(reaction.emoji.name === 'βοΈ')
//console.log('ROLE2');
user.addRole('id of role 2');
if(reaction.emoji.name === 'π§')
//console.log('ROLE3');
user.addRole('id of role 3');
}
});
Looks like you're trying to add a role to a User. When you should be adding the role to a GuildMember. As you can see here: messageReactionAdd returns a User. However Users don't have a .roles only GuildMembers do. However you have two ways you can get the GuildMember easily:
This way you have to make sure the message is from a TextChannel not a DMchannel.
if(reaction.message.type === "text") let member = reaction.message.member;
OR
This way allows the user to react to ANY message the bot has cached.
let member = bot.guilds.get('<id of the server>').members.get(user.id);
Then you do what #Syntle said: member.roles.resolve('<id of role>');
The choice of how to get the member is up to you.
user.addRole() needs to be replaced with member.roles.add.
msg.guild.channels.find(c => c.id == "693088078168064051").send(tempVars("absence_review"))
.then(function(message) {
const approved = message.react("β
")
.then(() => message.react("β"))
.catch(error => {});
const filter = (reaction, user) => {
return ['β
', 'β'].includes(reaction.emoji.name) && user.id === message.author.id;
};
message.awaitReactions(filter, {
max: 1
})
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === 'β
', reaction.user.bot === false) {
message.reply('reacted with yee.');
} else if (reaction.emoji.name === 'β', reaction.user.bot === false) {
message.reply('reacted with nah dude.');
}
})
.catch(collected => {
message.reply('you didnt react idiot');
});
That is the code I am currently using for the command. What I am making this command to do is to record an absence, send it to another channel with reactions, have someone react to it and if they react with the checkmark, it will send it back to the channel where the command was originally sent, but if they react to the cross, the person who originally made the command gets DM'd by the bot. Those last few things are easy, but my main issue is the reactions. I have made the reactions appear, but the last bit of the code seems to break it. Everything after the 'const filter' bit. If I remove all that, then it will just send the embed message with the reactions, but the reactions won't do anything. However, if I keep that in. It won't even send the message, I get an error stating "SyntaxError: Unexpected end of input" Now I have googled for this for around an hour, getting friends to help but unfortunately nothing is helping. If anyone could help it would be greatly appreciated, thanks in advance.
Although I cannot see the whole code, I believe your error is thrown not from the code above. The syntax error 'unexpected end of input' is usually caused by not finishing a bracket or brackets i.e )}; in somewhere in your code - commonly after the 'client on' function in your main.js file. Go through your whole code and make sure every bracket is properly represented. Maybe put your code into code.vb - it detects and points out syntax errors like the one you have above.
Let me know of progress.
I have spent yet another 3 hours in my mini dungeon figuring this out and got something to somewhat work.
msg.guild.channels.find(c => c.id == "693088078168064051")
.send(tempVars("absence_review")).then(function(message){
message.react("β
")
.then(() => message.react("β"))
.catch(error => {});
});
const filter = (reaction, user) => {
return ['β
', 'β'].includes(reaction.emoji.name) && user.id === message.author.id;
};
message.awaitReactions(filter, {
max: 1
})
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === 'β
', reaction.user.bot === false) {
message.reply('reacted with yee.');
} else if (reaction.emoji.name === 'β', reaction.user.bot === false) {
message.reply('reacted with nah dude.');
}
})
.catch(collected => {
message.reply('you didnt react idiot');
});
This is a fixed version of it, although the last bit doesn't necessarily work, I will try figure the rest out by myself.
i have a problem with the message reaction, i made the bot to delete any message sent on channel names appeal and send it to another channel names the appeals and react to the message with :white_check_mark: and if someone reacted to the message with the :white_check_mark:, the bot will automaticly delete the bot,
thats working but there is a problem, if i restarting the bot and reacting to the message sent before the restarting , the bot don't deleting the message
why?
client.on('message', async message => {
if(message.author.bot) return;
var muted = message.guild.member(message.author).roles.find(j => j.id === "505763004797812766");
if (muted && message.channel.id === "563944611693854721"){
var muted = message.guild.member(message.author).roles.find(j => j.id === "505763004797812766");
const args = message.content.split(" ").slice(0).join(" ");
const appeal = new Discord.RichEmbed()
.setAuthor(message.author.username, message.author.avatarURL)
.setTitle(message.author.username + " appeal")
.setColor("RED")
.addField("Message", args);
message.guild.channels.find(ch => ch.id === "563966341980225536").send(appeal).then(msg => {
msg.react('β
');
client.on('messageReactionAdd', (reaction, user) => {
if(reaction.emoji.name === "β
") {
const whitecheckmark = (reaction, user) => reaction.emoji.name === "β
";
const done = msg.createReactionCollector(whitecheckmark, {time: 60000});
done.on('collect', r => {
msg.delete();
message.guild.channels.find(ch => ch.id === "563966341980225536").send(message.author + " Appeal ended by: " + reaction.users.last())
})
}
});
})
message.delete();
message.channel.overwritePermissions(message.author, {SEND_MESSAGES: false});
}
else if(!muted && message.channel.id === "563944611693854721"){
message.channel.overwritePermissions(message.author, {SEND_MESSAGES: true});
}
});
This is events by design. The only way you can get around this is by queuing these events in some kind of durable queue like RabbitMQ or NATS assuming the events make it to your listeners before it restarts.
In general, it isn't good practice to "nest" events (that is, add listeners within others). If you place the messageReactionAdd listener outside of the message event on its own, it will listen without needing a message to. Then, if the message is sent and the bot restarts, the reaction event will still be fired. Just make sure to confirm that the message triggering the event is indeed one that should be.
I searched it up and got a code with readline where it looks like this:
const Disc = require('discord.js');
const client = new Disc.Client();
const token = 'token'
const readline = require('readline');
client.login(token);
client.on('message', function(message){
if(message.channel.type === 'dm'){
console.log("[" + message.author.username + "]: " + message.content)
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('REPLY TO ' + message.author.username + ': ', (answer) => {
message.author.send(`${answer}`);
rl.close();
});
}
});
But it doesn't work helpp
This is a topic I just did recently actually, so I'll walk you through it and give you some code to go along with it.
First, I would like to say when your making a post, include a clear question. From what it sounds like, your asking for a bot that logs dms to the console, or responds to them. I will just answer both questions.
The easiest way to check for a DM is to see if the message channel type is DM. Check here for more info on the channel class. You can check if a channel is a certain type by doing this:
if (message.channel.type === 'dm'){ } // change dm to the type you want
This will have to go in your on message function, so right now, if you're following along, the code would look like this:
bot.on('message', async message => {
if (message.channel.type === 'dm'){ }
});
From there it's simply adding code to the inside of the if statement. You will always want a return statement inside of it just incase nothing happens, so it doesn't try to do anything in the channels.
For what you want, this will log the DM to the console and reply to it, if it is equal to a certain message.
bot.on('message', async message => {
if (message.channel.type === 'dm'){
console.log(message.content);
if(message.content === "something"){
return await message.channel.send("Hi!");
}
return;
}
});
This should do what you want, if you have any questions, comment it on here and I'll respond as soon as possible :)
edit:
bot.on('message', async message => {
if (message.channel.type === 'dm'){
console.log(`${message.author.username} says: ${message.content}`);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question(`REPLY TO ${message.author.username}: `, (answer) => {
message.author.send(`${answer}`);
rl.close();
});
}
});