Having different welcome channels - node.js

I need my discord bot to remember which channel to send a greeting to in different guilds.
For now, I have the channel name as a prefix and I use that to recall where to send it:
//greeting new users script
bot.on('guildMemberAdd', member => {
// Send the message to a designated channel on a server:
const WelcomeChannel = member.guild.channels.cache.find(ch => ch.name === config.WelcomeChannelVar);
// Do nothing if the channel wasn't found on this server
if (!WelcomeChannel) return;
const welcomeEmbed = new Discord.MessageEmbed()
.setAuthor(member.displayName.toString() + '#' + member.user.discriminator, member.user.displayAvatarURL())
.setTitle('someone joined!')
.setDescription('welcome to **' + member.guild.name + '**, <#' + member.id + '> !')
.setColor(0x348a58)
.setThumbnail(member.user.avatarURL())
.setFooter('you\'re member #' + member.guild.memberCount + '!')
setTimeout(() => {
WelcomeChannel.send(welcomeEmbed)
}, 200);
member.send("welcome to " + member.guild.name + "! please **read the rules**, and *follow them* :) if you need any help, please **ping a staff member**.");
});
How do I set a command that owners can use when the bot joins their guild that sets a unique welcome channel for each guild (and obviously only send welcome messages to people who join in their guild).
Oh, and how do I set a command that eventually lets people change the welcome message for their guild?
Thanks! :)

You need to have a file where you store the welcome channel IDs for every guild, so that you can later check them. You can just use a JSON file:
// Define it one time
const welcomeChannels = require('./path/to/your/file.json')
// When you want to set the channel for a guild
welcomeChannels[guild.id] = channel.id
fs.writeFileSync('./path/to/your/file.json', JSON.stringify(welcomeChannels))
// When you need to read a property
let welcomeChannelID = welcomeChannels[guild.id]
You can use a variable to store the object, which is saved to a file that you can update with fs.writeFileSync.
Inside the guildMemberAdd handler, you can get the guild id from the new member and then use it to get the channel id:
bot.on('guildMemberAdd', member => {
let id = welcomeChannels[member.guild.id]
let welcomeChannel = member.guild.channels.cache.get(id)
// The rest is the same as in your code
})
Example
In the main file you just need to require it for the first time and use it in your guildMemberAdd handler.
// main file
const welcomeChannels = require('./path/to/your/file.json')
bot.on('guildMemberAdd', member => {
let id = welcomeChannels[member.guild.id]
let welcomeChannel = member.guild.channels.cache.get(id)
// The rest is the same as in your code
})
For the command it really depends on your command system: you need to find a way of sharing the welcomeChannels variable across the files, which is typically done though import/export Here's a mock function on how to set a new value.
// command file
function setId(guildID, channelID) {
welcomeChannels[guild.id] = channel.id
fs.writeFileSync('./path/to/your/file.json', JSON.stringify(welcomeChannels))
}

Related

How to do a 'Report Bug' command with discord.js

I ve been trying to do a report 'bug command'.
This is my code so far:
bot.on('message', async (client, message, args) => {
let parts = message.content.split(" ");
if(parts[0].toLocaleLowerCase() == '!bugreport') {
const owner = client.users.cache.get('567717280759283883');
const query = args.join(" ");
if(!query) return message.channel.send('Bitte schildere den Bug').then(m => m.delete({timeout: 5000}))
const reportEmbed = new Discord.MessageEmbed()
.setTitle('Fehlermeldung')
.setThumbnail(message.guild.iconURL())
.addField('Fehler:', query)
.addField('Server:', message.guild.name, true)
.setFooter(`Gesendet von ${message.author.tag}`, message.author.displayAvatarURL({dynamic: true}))
.setTimestamp();
owner.send(reportEmbed);
}
});
The error code always says that 'content' is undefined, but I do not understand that
Assuming your bot is a Client, it seems you're expecting the message event to pass more arguments than it actually does. Although that would indicate you're trying to read content from undefined, not that content itself is undefined.
The Client#message event allows 1 parameter which is an instance of Message. Change your code to this
bot.on('message', async (message) => {
//code here
})
You probably got confused with message handlers, where you can customize the function to your liking.
The message event only passes the received message according to the discord.js docs.  Your event handler should look more like this at the start:
bot.on('message', async (message) => {
Note this won't completely fix your command, as you'll still be missing the args and client parameters. Here's my best guess as to where to get those from based on how you're using them:
const args = parts.splice(0,1); // gives array of everything after "!bugreport"
const client = bot; // alternatively, replace client with bot in your code

Discord.js AutoRole Reaction do nothing

my little problem is the next one :
When i react a message, my bot do nothing :D and it's not the objectives.
My events :
module.exports = async(client, messageReaction, user) => {
const message = messageReaction.message;
const member = message.guild.members.cache.get(user.id);
const emoji = messageReaction.emoji.name;
const channel = message.guild.channels.cache.find(c => c.id === '739163072064651296');
const lol = message.guild.roles.cache.get("763104201588473896"); //id role lol
const wz = message.guild.roles.cache.get("763104236119785584"); //id role wz
if (["lol", "wz"].includes(emoji) && message.channel.id === channel.id) {// lol = emoji name and wz too
switch (emoji) {
case "lol":
member.roles.add(lol);
message.channel.send('test')
break;
case "wz":
member.roles.add(wz);
message.channel.send('test')
break;
};
};
};
My events handler :
fs.readdir("./Events/",(error , f) => {
if(error) console.log(error);
console.log(`${f.length} events chargés`);
f.forEach((f) => {
const events = require(`./Events/${f}`);
const event = f.split(".")[0];
client.on(event, events.bind(null, client));
});
});
If someone can help it's perfect ! Thank you !
I tried to understand what you wanted to make but couln't understand you at all, your trying to make a autoRole sytem that listen's to reactions? AutoRole is supposed to be in a guildMemberAdd event, so if a member join's, you add a role automatically, but from the code you provided, it looks like it listen's to reactions on some message? If your trying to make a Reaction Role system, then follow this. Other than that, i can't help you.
If your trying to make a autoRole system follow this
From what i know, when you add a role to someone, you will have to do the following
member.roles.add("roleid")
But what your doing is basically this:
member.roles.add(message.guild.roles.cache.get("763104201588473896")) //as lol is defined like that
So, to fix it, instead of getting the role object, then trying to add the role to the user, do this, and be sure to make the file name "guildMemberAdd.js":
module.exports = async(client, member) => {
const lol = "763104201588473896" //id role lol
const wz = "763104236119785584"; //id role wz
member.roles.add(lol);
member.roles.add(wz);
};

Discord.js mentioning

client.on('message', message => {
if (message.content === `L!hug`) {
if (!message.mentions.users.size) {
return message.reply('you need to tag a user in order to hug them!!');
const taggeduser = message.mentions.users.first();
}
// message goes below!
message.channel.send(userID + ` you just got a hug https://tenor.com/view/anime-cuddle-cute-gif-12668750`);
}
});
I have tried a few ideas and I am very new to this library of language (discord.js)
You can use message.mentions.members.first()
client.on('message', message => {
if (message.content.startsWith('L!hug')) {
let targetMember = message.mentions.members.first();
if(!targetMember) return message.reply('you need to tag a user in order to hug them!!');
// message goes below!
message.channel.send(`<#${targetMember.user.id}> you just got a hug https://tenor.com/view/anime-cuddle-cute-gif-12668750`);
}
});
Discord.js uses many custom toString() and an User return his mention.
So if you want to mention an user in a message you can do
This :
`<#${user.id}>`
But a faster way is this :
`${user}`
And you can simply put user without any String it works also if the function runs a .toString() on your string.
like this :
message.channel.send(user + " has made something");
Will mention the user.
Note :
It won't work anymore in v13.
If you use a command handler like this one
this is how you would make it work
module.exports = {
name: "hug",
description: "# someone to hug them through the bot command.",
nsfw: false,
execute(message, args){
const targetmember = message.mentions.members.first()
if (!targetmember) return message.reply("you need to tag a user in order to hug them.");
var huggifs = [`${targetmember} Recieved a hug https://imgur.com/r9aU2xv`, `${targetmember} Recieved a hug https://tenor.com/LUqw.gif`, `${targetmember} Recieved a hug https://media.giphy.com/media/3ZnBrkqoaI2hq/giphy.gif`, `${targetmember} Recieved a hug https://tenor.com/1jRF.gif`, `${targetmember} Recieved a hug https://media.giphy.com/media/lrr9rHuoJOE0w/giphy.gif`]
var hugrandomform = huggifs[Math.floor(Math.random()*huggifs.length)];
message.channel.send(hugrandomform).then().catch(console.error);
}
}
Here, you can use message.mentions.users.first():
let user = message.mentions.users.first(); // As a shortcut to it
// Check if there is actually a mention
if(!user) {
return message.reply("You need to tag a user in order to hug them!");
}
// If there is a user, do this code
message.channel.send(`${user.toString()}, you just got a hug https://tenor.com/view/anime-cuddle-cute-gif-12668750`);
// user.toString() will convert the user object to a mention
Hope this helped!
Here is a simple version of the code. userID isn't defined, meaning you'd need to use the targetmember. Here, this is how it should be.
client.on('message', message => {
if (message.content === "L!hug") {
const targetmember = message.mentions.members.first()
if (!targetmember) return message.reply("you need to tag a user in order to hug them!!");
message.channel.send(`${targetmember} you just got a hug https://tenor.com/view/anime-cuddle-cute-gif-12668750`);
}
})
You can use this to create a mention (note that it will not work in pre, as no mention works in it)
'<#&' + user_id + '>'
Note the # and &.

Discord.JS: How to get first channel of a guild?

I am creating a Discord bot. I want to create invite by guild ID. Creating invite needs a channel. I want to bot to select the first channel. How can I do this?
I used this but did not work:
guild.channels[Object.keys(guild.channels)[0]]
//returns undefined
for v12 try
var chx = guild.channels.cache.filter(chx => chx.type === "text").find(x => x.position === 0);
If you mean first by position, you can look the channels up by type and position using the guild channels collection.
const channel = guild.channels.filter(c => c.type === 'text').find(x => x.position == 0);
I don't know what you're meaning by first channel, but you could use this :
const randomChannel = (guild) => {
guild.channels.random().then(channel => {
if (channel.type === 'text') return channel;
else return randomChannel(guild);
}
}
To get a channel to create an invite you should probably only use ones where the Bot has permissions in, eg:
const invitechannels = guild.channels.filter(c=> c.permissionsFor(guild.me).has('CREATE_INSTANT_INVITE'));
invitechannels.random().createInvite()
.then(invite=> console.log('Create Invite:\n' + invite.code))
Alternatively you could also check for existing invites:
guild.fetchInvites()
.then(invites => console.log('Found Invites:\n' + invites.map(invite => invite.code).join('\n')))
Each channel has a calculatedPosition property, which you can use to get the first channel.
const channel = Array.from(guild.channels).sort((a,b) => a.calculatedPosition - b.calculatedPosition)[0];
Alright let's break down what is happening in the above code:
Array.from(guild.channels) //returns an Array of GuildChannels (Textchannels and Voicechannels)
.sort((a,b) => a.calculatedPosition - b.calculatedPosition) //sorts the elements in the collection by their calculatedPosition property in ascending order and returns the array
[0] //returns the first element of the array
For Discord.js v13 try:
var chx = guild.channels.cache.filter(chx => chx.type === "GUILD_TEXT").find(x => x.position === 0);
Use "GUILD_TEXT" instead of "text".
For multiple types use this:
const _arr = ["GUILD_TEXT", "GUILD_NEWS", "UNKNOWN"];
var chx = guild.channels.cache.filter(chx => _arr.includes(chx.type)).keys());
More about channels' types read here:
https://discord.js.org/#/docs/discord.js/stable/class/GuildChannel?scrollTo=type

Send message to specific channel with typescript

I want to send a greeting message to an "welcome" text channel, whenever a new user joins the server (guild).
The problem I'm facing is that, when I find the wanted channel, I will receive the channel with the type GuildChannel.
Since GuildChannel has no send() function, I'm not able to send the message. But I can't find a way to find the TextChannel, so I'm stuck here.
How can I get to the TextChannel so that I'm able to use the send() message? Below the code I'm using by now:
// Get the log channel (change to your liking)
const logChannel = guild.channels.find(123456);
if (!logChannel) return;
// A real basic message with the information we need.
logChannel.send('Hello there!'); // Property 'send' does not exist on type 'GuildChannel'
I'm using version 11.3.0 of discord.js
Thanks to this GitHub issue I've found the solution to my problem.
I need to use a Type Guard to narrow down the correct type.
My code now is this:
// Get the log channel
const logChannel = member.guild.channels.find(channel => channel.id == 123456);
if (!logChannel) return;
// Using a type guard to narrow down the correct type
if (!((logChannel): logChannel is TextChannel => logChannel.type === 'text')(logChannel)) return;
logChannel.send(`Hello there! ${member} joined the server.`);
Maybe for latecomers who are still looking for an answer this worked for me
let channel = client.channels.get("channelid") as Discord.TextChannel;
channel.send("what you want to send to that channel");
You can use the GuildChannel#isText() method to type guard before invoking send.
Example:
if (channel.isText()) {
await channel.send('...');
}
Or:
if (!channel.isText()) return;
await channel.send('...');
Discord v14
const channel: TextChannel = client.channels.cache.get(channelId) as TextChannel;
channel.send('test')
If you have problems with cache, you can use
const channel: TextChannel = await client.channels.fetch(channel.channelId) as TextChannel;
I do this:
let channel = client.guilds.get('your-guild-id').channels.get('your-channel-id');
channel.send("it worked");
(client is the discord client). your code should work if you change find to get and put the channel id in some single quotes. Well, it works for me.
Maybe this can help you?
Code:
client.on('guildMemberAdd', member => {
let channel = member.guild.channels.find('name', 'welcome');
let memberavatar = member.user.avatarURL
if (!channel) return;
let embed = new Discord.RichEmbed()
.setColor('RANDOM')
.setThumbnail(memberavatar)
.addField(':bust_in_silhouette: | name : ', `${member}`)
.addField(':microphone2: | Welcome!', `Welcome to the server, ${member}`)
.addField(':id: | User :', "**[" + `${member.id}` + "]**")
.addField(':family_mwgb: | Your are the member', `${member.guild.memberCount}`)
.addField("Name", `<#` + `${member.id}` + `>`, true)
.addField('Server', `${member.guild.name}`, true )
.setFooter(`**${member.guild.name}**`)
.setTimestamp()
channel.sendEmbed(embed);
});

Resources