Discord.JS v13 - Welcome Message per Guild [Ep. 10]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone this is alex from wornoffkeys.com and in this video i'm going to show you how to create your own a configurable welcome channel so server owners are using your bots can configure a welcome message to be sent every time someone joins the server i'll also be showing you how to simulate a join with a custom simulate join command which will then simulate that you join so you don't have to use alt accounts to test out the new functionality now real quick i want to mention that knowing javascript is required to follow this video and this entire series if you don't know javascript don't worry you can scroll down to the description of this video and at the top you'll see javascript course there is an hour-long crash course here on youtube which you can right-click and open this in a new tab so you can watch that after you're done with this video so in this video i'll be using worn off keys commands as my command handler and if you prefer to use a different command handler then feel free to use that all the concepts will be the same as long as you know how to create your own commands so far i've told warnock keys commands where my command folder is as well as what test servers i have so we can register guild based commands for that test server now going into this episodes folder i want to make two more folders within here the first one will be called features which will basically hold all of our event listeners and the second one will be called models which will hold all of our mongodb schemas now this will be using mongodb that way it's fully customizable between multiple different servers and if you don't know mongodb i have an entire playlist here on youtube a link that can be found in the description down below so the first thing we have to do is create a schema within our models folder which will explain how our data should be stored within so i'm going to make a new file and i'm going to call this welcome schema dot ts and if you're using js of course you'd want to use js instead so within here we then need to import mongoose within javascript that'll be const mongoose equals require mongoose but within typescript that will be import mongoose from mongoose and if you don't already have mongoose installed you can install it with npm install mongoose i already have installed so i'm just going to cancel this and close my console now in addition to importing mongoose i also want to import schema which is what we need to create in order to map out how our data should be structured so i can now say const welcome schema equals new schema with an object and within here we can specify what type of data we're going to have now there are three properties here and all of them are going to be required strings so i'm going to create a constant here called a rec string which stands for required string and i'm going to say type is string and required is true this is stuff we have to specify for all three of the properties we're going to soon add into our schema and so making it into this one object that we can reference here will save us time so the first thing we need is underscore id which is known as the primary key within a mongodb schema so here we want to specify that this is going to be a required string and because underscore id isn't very descriptive i'm going to add in a comment saying this will be the guild id next we're going to have the channel id which will also be a required string and then also text which will of course be a required string so with these three pieces of information we can now specify what channel is going to be welcoming users into what guild as well as what message to send as the text next we're looking to name this schema and so i'm going to say const name equals welcome tutorial and then we're going to export this within javascript that would be module.exports equals and in typescript that would just be export default now what comes afterwards is the same for both javascript and typescript and we want to essentially try and receive the model if it's already been created otherwise we want to create it so here we can say mongoose.models with an s and we see that this is an object but model without an s is going to be a function so this function will create the model and then behind the scenes store inside the models object and so with that said we want to first see if it's already been created so we can say models index of name or we could then call the model method so mongoose dot model we can then pass in name and then our schema which is welcome schema and by default this will work so far but mongoose will actually add in an s to the end of this because it wants everything to be plural this is something i personally don't want and so what i can do is pass the name again and so having the name as the third argument will force mongoose not to add in any s's to the end of this so now our schema is ready we're now ready to create our configuring command to actually set our schema data so i can save this and inside of our commands i'm going to create a new file called set welcome dot ts and again if you're using javascript you would use js instead but within here we can now export an object within javascript i can say module.exports equals an object but within typescript i can say export default object and if you're also using typescript we can specify what type of object this is by saying as i command and i command is an interface within one of keys commands which gives us additional information about what can be inside this command so let's start off with the category where i will say configuration and the description will then say sets the welcome channel and we want to make sure that only certain people can use this command this will be an array of strings we'll pass an administrator we also want a certain number of arguments to be provided so i could say the minimum number of arguments is two and there is no maximum by default so we'll just keep that the same but we also want to specify our expected arguments so within here i can say channel as well as text so the channel will be a mention of the channel that we want to actually send welcome messages in and the text can be the actual message that is sent to the user now i also want to provide support for a slash command as well as a legacy command so we can do exclamation point set welcome as well as forward slash set welcome and one of keys commands makes this really easy to do so i can say slash is a string of both and we only want to register guild based slash commands when testing and because i've already specified my test servers here where you would want to specify your own test guild id we can now say test only is true this will make this command whether slash commands or legacy commands only work in the specified testing servers and once the command is fully working you can then comment this out that way it'll create a global slash command in all servers using your bot so i'll uncomment this for now and if you're familiar with slash commands you might be familiar with the concept of options you can actually pass on your own custom options object into one of keys commands just like this now if you did not specify options behind the scenes one off keys commands will automatically infer your own options from the arguments here but it will always use strings as these because it does not know what type we want because we want to mention a channel i want to make sure that this first argument is going to be its own channel mention and so with that said we have to pass in our own custom options here this is actually fairly simple to do here we can say name which i'll say is channel we can have a description which i will say the target channel i can then have required is true and now i want to import discord.js at the top of my file so i can import djs from discord.js now within here i can specify the type which will be djs dot constants the application command option types dot channel and this is the reason here why we want to specify our own options because this will give the user a drop down where they can specify what channel they want to use now we also need to provide information about the second command here which is the string so here we can say name is text the description is the welcome message we can say required is true and the type will be djs.constance.applicationcommandoptiontypes.string now after the options we can have our callback method which we ran every single time a user actually runs this command we can add in our own object here to destructure some properties from this and we also want to make this an asynchronous function because we will be using a weight inside of it so inside of here we need a couple different pieces of information such as the guild the message the interaction and the arguments now message is passed in only for legacy commands and interaction is passed in only for slash commands so interaction will be null if we did exclamation point set welcome and message will be null if we did forward slash set welcome so that is one thing to keep in mind and before we actually write this code we need to import our schema so i can say import welcome schema from we can go back into our models folder and access our welcome schema there now inside of here we want to first gain access to the mentioned channel and we want to do that whether or not it was a legacy command or a slash command like i say const target equals now here we'll use a ternary operator so if message does exist we're going to say message dot mentions dot channels dot first or we'll say interaction dot options dot get channel and here we can pass in our own string that has to be the same exact name as this right here so i'll pass in channel and now we have access to our channel here so we want to make sure this channel exists as well as make sure that this is a text channel so i can say if not target or target dot type is not exactly equal to guild underscore text so in the case of a legacy command where message exists we might not actually tag anything and so in that case this here will be undefined so this is why we're checking not channel and also within either of these options the user could specify a voice channel for example and so we need to specify the type here must be guild text so if the channel doesn't exist or if the type is not equal to guild text we then want to tell the user to actually tag a text channel now in one of key's commands you can simply return a string and this will apply to either the legacy command through the message or the slash command interaction so i can simply say return please tag a text channel now afterwards we know for sure that we have access to a text channel we now want to get the actual text that the user provided here or as a second argument here so what i'm going to do is i'm going to create a variable using let and i'll call this text i'll set this equal to interaction with a question mark dot options dot get string here we'll pass in text because that's the same exact name as we specified in our options object here and this question mark is known as optional chaining so essentially this will make sure that interaction actually exists it's very similar to saying if interaction then text equals interaction dot options etc so it just makes our code a little cleaner and easier to read and now what i want to do is i want to see if message actually exists so if message now if this is the case this was actually run as a legacy command such as set welcome or some other type of prefix like that and so with that said we know that interaction is going to be null in that case because interaction is only there if it's a slash command which means the optional chaining here would make this text undefined so we need to gain access to the text from the actual legacy command so now one thing to keep in mind is that we also have this channel argument first and we don't want that to be part of the actual messages sent so we need to first remove that so this args property here will be an array of every individual word that is sent so what we want to do is first remove the first index by saying args.shift and then afterwards we should be left with an array where each individual word is an element so i can say text equals args.join with a space and so this will essentially turn our array of different words into a normal sentence so so far we have access to our channel as well as the message and the guild so we can go ahead and save this information into the database there's a couple ways to do this within mongodb and one way i want to do this is to make sure that we can update this later on so we can use find one and update i'm going to go ahead and write the code and then i'll explain what each step does afterwards so i can say await welcome schema dot find one and update and we'll pass in three empty objects here the first one is going to be the actual search to do so in this case we want underscore id to be our guild id so i could say guild.id and here we're getting this error because guild is possibly null and that's actually something we might want to check just in case the user is running this inside a direct message so at the very top of the callback i can say if not guild which is only going to be the case if they're running a command outside of a guild such as in a direct message i can return saying please use this command within a server so because of this we now know that guild was going to be valid because otherwise we would have returned back here so this is the search to provide against our schema here and as i mentioned underscore id is the guild id so it's going to try and find one item in our collection that matches this and then it's going to take the data in the second object here and it's either going to insert it or update it so here we have to also specify the same thing of guild.id then we can specify text as well as channel id being target.id we just specify upsert is true this is a combination of insert and update so basically if something exists with this id it will then update it with the new information here so server owners can still update the text or update the channel but if this doesn't exist it would then insert it using all this information here so now afterwards we want to let the user know that the channel was actually set so i can say return welcome channel set and before we actually listen for new joins or before we simulate joins we want to make sure this actually works so if i save this and i go into my console i can use npm run dev to start my bot now i'm about to go into my mongodb console which does not have a dark mode yet so if you're in a dark room watch your eyes because the screen will get bright here i'm on my welcome tutorial if you don't see that within your mongodb console you can go ahead and click on refresh at the top right and try and find it on the left panel here so within here by default there will obviously be zero and i can click on apply to search again and so far there's nothing in here but if we try and run that command we should actually see it work so i could do forward slash set welcome here we can specify a channel and this is why we provided the options object because we can now select anything here i'm going to select a voice channel specifically just to make sure that we can only provide a text channel now the actual text i'll just say test for now and it'll then say please tag a text channel if i use set welcome and say test test where this first argument should be a channel tag it should say the same thing so now we know that that check works i can now say set welcome i can specify the welcome channel and for the text i can then say welcome at to the server now the at symbol here will be a placeholder to actually mention the user so then i can run this command and we actually get an error because i forgot to mention that we do not have a mongodb connection set up within one of keys commands now if you've already manually created your own mongodb connection within your bot then that probably worked for you but if you're using one of keys commands we can specify our uri here which i have stored in my dot enb file like i say process.in.mongo underscore uri of course yours might be different and that'll be your own unique login for your and this will be your own unique login stream for your server which you can get on mongodb.com and if you don't know how to do that again i have a complete mongodb series on youtube so you can check that out in the description down below so i'm going to go ahead and save this and we should connect to our mongodb database where then we can actually use this and save things to our schema so if i go back into my server i can do forward slash set welcome i can specify the welcome channel and then the text i can say welcome at to the server if i run this it'll then say welcome channel set if i go back into mongodb i can click on apply and here we see the guild id right here the channel id right here and the text welcome at to the server so each individual guild that uses your bot can have its own record here and then what we can do is we can load that whenever someone joins and then send them a message so going back into vs code i can close my bots and i can minimize my console i now want to listen for whenever new people join the server and so we can do that within our features folder here i can make a new file and call this welcome.ts and of course use.js if we're using javascript within here we're looking to export a function like i say export default client this is the parameter which we can specify as an actual discord.js client and we can also export a constant known as config which is an object and this is something specifically for one off keys commands this basically provides some information about this feature so in the future once one of these commands allows server owners to disable or enable certain features they have the ability to do so there are only two properties with the pass in the first one is our display name which is basically what the users will see in this case i'll say welcome channel and then we also have our db name which should never be changed even if you change this display name here the db name is what will be stored inside the database and so i'm going to say welcome underscore channel and while the exact capitalization and formatting doesn't actually matter i'm writing it like this just so i know in the future that this is the db name because obviously this isn't the type of formatting we would use when displaying something to a user so now within this function here we can go ahead and listen to new people joining by saying client.on guild member add and then we'll have access to a member here and we want to make this function called asynchronous because we'll be using our schema which we also need to import so import welcome schema from we'll go back to our models and access our welcome schema and now here we want to get access to the text for this guild and then send that to the message but one thing we want to keep in mind is that we do not want to reach into the database every single time so there are two ideal solutions to this where we don't have to reach into the database every single time the first of which is going to be load all the data when the bot starts up the second option will be load and store the data only when needed so i'm going to use the second option here and basically this means that we will store all the needed data inside of our current process memory and if it doesn't exist there we will then fetch it from the database and then store in memory so with that said i'm going to create an object to store all the information we need so i can say const welcome data equals an object and if you're using typescript you'll want to specify what type of data will be stored here so i can say as an object and then here we can specify that the key will be a string and we're actually looking to store an array here now the brackets here have no correlation with these brackets here we would use the brackets on the key even if we were storing a string or a boolean or some other type of data like that we just happen to also be storing an array and in this array i want to specify a text channel as well as a string and this string will be the actual text to send and this key here will be the guild id so to make this super clear i'm going to add in a comment here saying guild id colon channel and then message this way it's a little more descriptive of what we're actually storing here and again all of this code should not exist here if you're using standard javascript this should only exist if you're using typescript so now here i'm looking to access first the guild and the id of this member so i can say const guild id equals member and now we want to access the data from the welcome data object so i'm going to use a let here so i do plan on changing this value in the future select data equals welcome data index of guild id because again the key here is a guild id as we specified right here so now what i want to do is i want to say if not data which means we have not stored this into local memory we then want to fetch it from the database and then store in local memory so i can say const results equals awaits which is why i made this function asynchronous here so await welcome schema dot find by id we can pass in the guild id so we can use this method because our underscore id property here is meant to be the guild id and so it'll essentially just find where underscore id equals guild id so here i can say if not results which means that no welcome channel is configured for the server we can just simply return so here i want to get access to the channel id and the text inside their own variables so we can destructure those channel id and text equals results and now we want to gain access to the actual channel from the channel id so i can say const channel equals guild channels and pass in the channel id and now we can assign this information into our data variable here so we can have access to it after this if statement but more importantly we can also assign it into our welcome data so in the future we don't have to fetch it from the database so i can say data equals welcome data index of gilda id equals and this will basically just assign this here to both of these variables right here so let's replace this right here with an array we can pass in channel and text and this is the same array format that we see right here where we have an actual channel and text now if you're using typescript you might get an error here because this is going to be a generic channel not necessarily a text channel so if you're using typescript at the end of this we can say as text channel and so tell it that this is meant to be a text channel which makes this error go away right here so now outside of this if statement we now know that either we pulled our data locally from memory or we fetched it from our database and then stored it in memory so either way we have access to the information we need so i can say data index 0 which is our channel dot send i can then pass in an object where we can have content which will be equal to data index one which is our actual text here as the message but we want to replace the at symbol with a mention of the actual user so i can say don't replace we can then say forward slash at forward slash g which will replace all instances of the ad symbol with the users at and then the string here will be what we actually want to replace it with so i'm actually going to use template literals and i'm going to say less than at symbol greater than and this is the syntax to actually mention someone within discord so in between the at symbol and the greater than symbol i can pass in id which we just structured up here and this will actually replace the at symbol here on all instances of the message with an actual mention so now i can save this and we need to make one more simple command to simulate a join if you have an alt account handy you can go ahead and use that but this command is incredibly simple so i'm just going to go ahead and make it so i can say semjoin.ts we're going to export an object here as i command and here the category will be testing the description will be simulates a join we can have slash as both and test only as true now here we can have a callback and we want to destructure the member as well as the client so here we can say client.emit which will send an event on the client object which is the exact same thing that happens when someone actually joins the discord server so this event will be guild member add which happens to be the exact same thing we're listening to right here and so we have to pass in a member so it has access to the member so we're just going to simulate ourselves here we go here now because this is used as both a slash and legacy command we do want to return something because slash commands do expect a response so i can say return join simulated now if i save this and i run our bot using npm run dev i can now go into discord and i want to set the welcome channel again using another message so i can say set welcome specify the welcome channel and the message is going to be welcome at to the server and just to prove that all instances of the ask symbol will be replaced with dimension i can say at here again and i'm going to use a dot as a period and then i can go ahead and send this it'll say welcome channel set i can then use a simulate join and it'll say join simulated but nothing actually happens and that's because we have to go back into our index file we have to specify where our features files live so here under command store like i say featuresdir is path.join underscore underscore their name and then features of course if you use a different folder name you'd want to specify that here so i can save this i can then go back into discord i can do accumulation point simulate join it'll say join simulated and here it's going to say welcome at alexander flores to the server and it has my app again here now the last thing i want to show you is how to disable mentions here in case you do not want this tagging users oftentimes you do but just in case you don't you can go over to your welcome file whenever you're sending the message and here we can pass in allowed mentions as an object and here we can allow different types of mentions from replied users roles or users and we can simply pass in an empty array here as users and this will now no longer tag anyone so if i save this and i go back into discord i can go into general and i can try forward slash simulate join this will then send a new message here but as you can see i'm not being tagged thanks for watching the video if you want access to video source code as well as early access to future tutorials consider clicking on the join button down below the video to support the channel
Info
Channel: Worn Off Keys
Views: 3,079
Rating: 5 out of 5
Keywords: discord bot tutorial, discord.js tutorial, discord.js, how to make a discord bot, how to code a discord bot, code your own discord bot, how to program a discord bot, creating a discord bot, discord.js v13, discord bot tutorial 2021, discord bot tutorial for beginners, discord bot tutorial javascript, discord bot tutorial node js, worn off keys
Id: my-nVaJ76xc
Channel Id: undefined
Length: 26min 39sec (1599 seconds)
Published: Mon Sep 27 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.