AdvancedHandler
AdvancedHandler is a Discord.JS handler made by OzguYalcin. The goal of this package is to make it simple and easy to get your bot off the ground without worrying about your own command handler.
Installation
NPM
npm install advancedhandler
Topics
Setup
Here is a basic example of how to setup AdvancedHandler. When calling the constructor you can pass in an options object that configures AdvancedHandler to how you want. Here is a full example of all options:
index.js
const DiscordJS = require('discord.js');
const AdvancedHandler = require('advancedhandler');
const client = new DiscordJS.Client();
client.on('ready', () => {
new AdvancedHandler.CommandHandler(client, {
commandsDir: 'commands',
defaultPrefix: '$',
defaultLang: 'en',
ignoreBots: true,
showWarns: true,
disableCommands: [
],
botOwners: [
'ownerId'
],
testServers: [
'testServerId'
],
messagesPath: '',
mongoURI: 'MONGODB_CONNECTION_URI',
dbOptions: {
keepAlive: true,
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false
},
errorMessageDelete: 1000 * 60 * 2,
disableCommandWhenException: true
}).run();
new AdvancedHandler.FeatureHandler(client, 'features');
client.login("YOUR SECRET TOKEN");
})
CommandHandler Main File Methods
Here the methods for using in main file:
new AdvancedHandler.CommandHandler(client)
.setIgnoreBots(true)
.setShowWarns(true)
.setTestServers([
'ID1',
'ID2',
'ID3'
])
.setMessagesPath("your path here")
.setHelpSettings({
embed: {
color: "RED"
},
authoritativePerms: [
"ADMINISTRATOR",
"KICK_MEMBERS",
"BAN_MEMBERS"
],
categories: [
{
name: "Admin",
emoji: "emoji ID",
custom: true,
hidden: true
},
{
name: "Configuration",
emoji: "🔨",
custom: false,
hidden: false
}
]
})
.setDefaultLanguage("en")
.setDefaultPrefix("$")
.setMongoURI("YOUR MONGODB CONNECTION URI")
.setDbOptions({
keepAlive: true,
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
})
Commands
Shortcuts
Ping-pong Command Example
AdvancedHandler is easy to get setup and working. On this page you will learn how to create a simple "Ping -> Pong" command example.
First you must setup AdvancedHandler in your main file:
index.js
const DiscordJS = require('discord.js')
const { CommandHandler } = require('advancedhandler')
const client = new DiscordJS.Client()
client.on('ready', () => {
new CommandHandler(client, {
commandsDir: 'commands'
})
})
client.login("YOUR TOKEN HERE")
Then create a "commands" folder where you can create a "ping.js" file with the following contents:
module.exports = {
category: 'Fun',
description: 'A simple ping pong command.',
callback: ({ message }) => {
message.reply("Pong!")
}
}
After inviting your bot to a Discord server and running !ping ("!" is the default command prefix) within that server, your bot should reply with Pong!.
Command Properties
This page assumes you have a basic bot running using AdvancedHandler as seen here.
There are many options you have when it comes to commands, all are optional aside from a callback function which could alternatively be named run or execute as well.
All commands are exported as objects who have properties to dictate the command's functionality. Here is a complete list of all current properties available to you:
module.exports = {
name: 'ping',
aliases: ['p'],
category: 'Fun',
description: 'A simple ping pong command.',
usage: {
minArgs: 0,
maxArgs: 2,
params: [
"<test>",
"[test_2]"
]
},
requiredPermissions: ['ADMINISTRATOR'],
requiredBotPermissions: ['MANAGE_GUILD'],
cooldown: '10s',
globalCooldown: '10h',
userCooldown: '10m',
ownerOnly: false,
testOnly: false,
guildOnly: false,
init: (client, instance) => {
console.log('ran only one time when the bot starts up')
},
callback: ({
message, // The DJS message object
channel, // The DJS channel object
args, // An array of arguments without the command prefix/name
text, // A joined string of the above arguments
client, // Your bot's client object
prefix, // The prefix used to run this command
instance, // Your CommandHandler instance
}) => {}
}
Correct argument usage
You can specify the exact arguments and the minimum/maximum number of arguments for each command. If the user provides an incorrect number of arguments then CommandHandler will automatically tell them the correct usage based off of the command properties you provided. Here is an example:
add.js
module.exports = {
category: 'Math',
description: 'Adds two numbers together',
usage: {
params: ['<Number 1>', '<Number 2>']
minArgs: 2,
maxArgs: 2,
}
callback: ({ channel, args }) => {
const number1 = parseInt(args[0])
const number2 = parseInt(args[1])
const sum = number1 + number2;
channel.send(`The sum is ${sum}`)
}
}
If the user runs !add or !add 5 your bot will respond with Incorrect usage! Please use !add <Number 1> <Number2>. If the user runs !add 5 10 it will then respond with The sum is 15.
Bot owners only command
Some commands should only be available to the bot owners. A perfect example of this is a "status" command that updates the status of your bot. CommandHandler comes with this capability.
Here is how your command file should be setup:
status.js
const setStatus = (client, status) => {
client.user.setPresence({
status: 'online',
activity: {
name: status
}
})
}
module.exports = {
category: 'Math',
description: 'Adds two numbers together',
minArgs: 1,
expectedArgs: '<Status>',
ownerOnly: true,
callback: ({ client, text, message }) => {
setStatus(client, text)
message.reply('Status set!')
},
}
Whenever we initialize AdvancedHandler we can pass in any number of IDs for the owner's Discord accounts:
const DiscordJS = require('discord.js')
const { CommandHandler } = require('advancedhandler')
const client = new DiscordJS.Client()
client.on('ready', () => {
new CommandHandler(client, {
commandsDir: 'commands'
})
.setBotOwners(['your account ID', 'another ID', 'another ID'])
})
client.login("YOUR TOKEN HERE")
Test servers
You may want some commands to only be enabled in specific servers/guilds for testing. This will give you a good idea if something is working in a production environment without risking bugs for your other users.
You can easily specify a command as a "test only" command like so:
add.js
module.exports = {
category: 'Math',
description: 'Adds two numbers together',
testOnly: true,
expectedArgs: '<Number 1> <Number 2>',
minArgs: 2,
maxArgs: 2,
callback: ({ channel, args }) => {
const number1 = parseInt(args[0])
const number2 = parseInt(args[1])
const sum = number1 + number2;
channel.send(`The sum is ${sum}`)
}
}
You can then specify any amount of server/guild IDs when initializing AdvancedHandler like so:
index.js
const DiscordJS = require('discord.js')
const { CommandHandler } = require('advancedhandler')
const client = new DiscordJS.Client()
client.on('ready', () => {
new CommandHandler(client, {
commandsDir: 'commands',
testServers: ['850796991976964136', 'another ID', 'another ID']
})
})
client.login("YOUR TOKEN HERE")
Handling command errors
CommandHandler sends an error message by default, however you might want to customize this more and perhaps send an embed instead of a normal message. You can listen to command errors to achieve this.
Note: If you use "error" all default errors will disabled
Here is a list of all command errors you can listen for:
| GUILD_ONLY_COMMAND | null |
| USER_IN_BLACKLIST | message member |
| COMMAND_DISABLED | command object |
| CHANNEL_DISABLED | channel the message was sent |
| TEST_ONLY | message guild or "dm" |
| BOT_OWNERS_ONLY | message author |
| MISSING_ROLES | commands all required roles list |
| MISSING_PERMISSION | permissions the usser needed |
| MISSING_BOT_PERMISSION | permissions the bot needed |
| COOLDOWN | cooldown finish date |
| SYNTAX_ERROR | command text |
To listen to command errors you can pass an error function in your command object like so:
ping.js
const { MessageEmbed } = require('discord.js')
module.exports = {
category: 'Fun',
description: 'A simple ping pong command.',
callback: ({ message }) => {
message.reply('Pong!')
},
error: async ({ error, message, info, command, instance, guild }) => {
if(error === "GUILD_ONLY_COMMAND") {
return message.reply("This command can just run in a server!");
}
}
}
Command cooldowns
You can use command wait times to ensure that your commands are only run at frequent intervals. This is very useful for daily or weekly commands. There are three types of cooldowns in CommandHandler: Guild cooldowns are one system per guild. It waits even if the user doesn't use that command. User wait times are per user system. The user waits even if the server is different. But cooldown is for a server and the user on that server. User and guild must be the same for wait.
Each cooldown type requires a string for its duration and duration type (seconds, minutes, etc.).
| s | Seconds | 1 | 60 | 5s |
| m | Minutes | 1 | 60 | 10m |
| h | Hours | 1 | 24 | 5h |
| d | Days | 1 | 365 | 10d |
Example of per-user-guild cooldowns:
daily.js
module.exports = {
category: 'Economy',
description: 'Gives you daily rewards.',
cooldown: '24h',
callback: () => {}
}
Example of per-user cooldowns:
daily.js
module.exports = {
category: 'Economy',
description: 'Gives you daily rewards.',
userCooldown: '24h',
callback: () => {}
}
Example of per-guild cooldowns:
rewards.js
module.exports = {
category: 'Economy',
description: 'Rewards every user who reacts to the message.',
globalCooldown: '7d',
callback: async ({ message, channel }) => {
const { member } = message
const emoji = '💰'
const text = `React with ${emoji} to get rewards! Thanks to ${member} for hosting this reward giveaway!`
const newMessage = await channel.send(text)
newMessage.react(emoji)
}
}
You must have database for use this feature
Required user and bot permissions
You can only want your commands to be run by users with certain Discord permissions. This is usually useful for auditing tools, you just want your staff to be able to use this command.
Using AdvancedHandler you can easily determine what Discord permissions your users and bot need to run the command:
kick.js
module.exports = {
category: "Moderation",
description: "Kicks a member",
expectedArgs: "<Target user's @> [Reason]",
minArgs: 1,
requiredPermissions: ['ADMINISTRATOR'],
requiredBotPermissions: ['KICK_MEMBERS'],
guildOnly: true
callback: ({message, args}) => {
const target = message.mentions.members.first();
if (!target) {
message.reply("Please tag someone to ban!");
return;
}
if (!target.bannable) {
message.reply("This bot does not have the ability to ban that user!");
return;
}
args.shift();
const reason = args.join(" ");
target.ban({
reason,
days: 5,
});
message.reply(`Banned ${target}!`);
}
}
Command categories and help settings
For categories and other settings to display in the built-in help menu, you must specify them when starting AdvancedHandler.
This can be done as follows:
index.js
const DiscordJS = require('discord.js');
const { CommandHandler } = require('advancedhandler');
const client = new DiscordJS.Client();
client.on('ready', () => {
new CommandHandler(client, {
commandsDir: 'commands'
})
.setHelpSettings({
embed: {
color: "GREEN"
},
authoritativePerms: [
"ADMINISTRATOR",
"KICK_MEMBERS",
"BAN_MEMBERS"
],
categories: [
{
name: 'Admin',
hidden: true,
emoji: "🪓",
custom: false
},
{
emoji: "861615112750366731",
custom: true,
name: 'Example',
hidden: false
}
]
})
}
Instance Methods
AdvancedHandler has many functions that will make your job easier. These methods make it easier to write your code.
Here's All:
Message methods
getMessage
This method is for get message from messages file. This method will translate and replace the text automatically.
messages.json snippet
{
"TEST": {
"en": "Just a test text!",
"tr": "Sadece bir test metini!"
}
}
For get "TEST" you should use this:
test.js
module.exports = {
callback: async ({ message, instance }) => {
const { guild } = message
return message.reply(await instance.getMessage(guild, "TEST"));
}
}
If you ran the !test in a server it will reply with "Just a test text!". If that server was configured to Turkish it will reply with "Sadece bir test metini!" instead.
You can set dynamic placeholders in your messages like so:
messages.json snippet
{
"EXAMPLE": {
"en": "An example message. {TEST}",
"tr": "Bir örnek messajı. {TEST}"
}
}
You can then dynamically insert values like so:
example.js
module.exports = {
callback: ({ message, instance }) => {
const { guild } = message
message.reply(await instance.getMessage(guild, 'EXAMPLE', {
TEST: 'hello world'
}))
},
}
Now running !example will now display An example message. hello world
For get objects (embeds):
messages.json snippet
{
"HELP": {
"TITLE": {
"en": "Need help? Here are all of my commands:",
"tr": "Yardımamı ihtiyacın var? İşte tüm komutlarım:"
},
"DESCRIPTION": {
"en": "Use {PREFIX}help followed by a command name to get more additional information on a command. For example: \"{PREFIX}help prefix\".",
"tr": "Bir komut hakkında daha fazla bilgi almak için {PREFIX}help ve ardından bir komut adını kullanın. Örneğin: \"{PREFIX}help prefix\"."
}
}
}
For get "DESCRIPTION"
await instance.getMessage(guild, "HELP.TITLE", {
PREFIX: prefix
})
createSyntaxError
This method will create new syntax error.
example.js
module.exports = {
usage: {
params: [
"<tag user>"
]
}
callback: async ({ message, instance}) => {
let user = message.mentions.users.first();
if(!user) {
return await instance.createSyntaxError(message, commandName, 0, "REQUIRED_PARAM");
} else {
return message.reply(`You tag thi guy "${user}".`)
}
}
}
If you ran !example it will return you Incorrect usage! Please use \"!example <tag user>\". If have no "expectedArgs" its return you Incorrect usage! Please use \"!example\". So you should add "expectedArgs".
Language Methods
setLanguage
This method will set new language to the mongo database.
await instance.setLanguage(guild, "tr")
getLanguage
This method will get the guilds language. If have no guild return the default language. If have no default language, default language will "en" (english)
await instance.getLanguage(guild);
If you ran this command it will return "This guild language is "en"."
Prefix methods
setPrefix
This method will set new prefix to the mongo database.
await instance.setPrefix(guild, prefix)
getPrefix
This method will get guild prefix. If have no guild will return default prefix.If have no default prefix, default prefix is "
await instance.getPrefix(guild);
Command methods
isCommandHas
This method check the command has or not. Aliases will work too
instance.isCommandHas("command name")
getCommand
This method will return the command object you write. Aliases will work too but if you write aliases command.name will not the aliases.,
instance.getCommand("command name")
isCommandDisabled
This method will check the command disabled for the guild. Aliases will work
await instance.isCommandDisabled(guild, "command name");
isChannelDisabled
This method check the channel is disabled for the command. Aliases will work
await instance.isChannelDisabled(guild, channel, "command name")
mongoDB methods
isDbConnected
This method will check the mongoDB connected or not.
instance.isDbConnected()
getDbConnectionURI
This method will return the mongoDB connection uri
instance.getDbConnectionURI()
Features
A "feature" within AdvancedHandler is a normal feature within your bot. This could be a "reaction roles" system, or a "welcome message" system. A feature could include multiple event listeners and other logic to handle how your bot works. AdvancedHandler makes it easy to register features by adding them to a features folder.
The folder name can be specified when initializing AdvancedHandler like so:
index.js
const DiscordJS = require('discord.js');
const AdvancedHandler = require('advancedhandler');
const client = new DiscordJS.Client();
client.on('ready', () => {
new AdvancedHandler.FeatureHandler(client, 'features');
})
client.login("YOUR TOKEN");
You can then create a "features" folder and all of your features can be placed in that folder. These files will be automatically imported and ran and it is assumed that these files will export a function like so:
welcome-message.js
module.exports = (client) => {
client.on("guildMemberAdd", (member) => {
const { guild } = member
const channel = guild.channels.cache.find(
(channel) => channel.name === "welcome"
)
if (!channel) {
return
}
channel.send(`Welcome ${member} to the server!`)
})
}
This feature will be automatically ran and it's exported function will be invoked. This way you can easily register listeners and handle each of your feature's.
Built-in Commands and Features
Shortcuts
Seting removing and cleaning blacklist
Advancedhandler comes with the ability for bot owner(s) make some users can or not use the bot's commands. Also this command can clean the the all blacklist. They can do this easily with the following command:
(For use this command you should specified the bot owner(s). If you don't specified the bot owner(s) command can't be used.)
!blacklist <set | delete | clean> <tag user | userId>
Enabling and disabling commands
AdvancedHandler comes with the ability for server owners using your bot to enable or disable commands within their server/guild. They can do this easily with the following command:
!command <enable | disable | clean> [command]
Configurable required roles
Server/guild owners can configure what roles are required to use specific commands. This is not done through IDs or role names as those will vary between each guild. Instead each server owner can run a command to specify what role is required or unrequired to use a command like so:
!required-roles <add | remove | clean> [command] [role id | mention role]
If you use the "remove" option it will make the role unrequired
Per-guild prefixes
Server/guild owners can configure what prefix your bot uses by using the following command:
!prefix <prefix>
Omitting the prefix will display the current prefix for that server/guild. The default prefix for AdvancedHandler is a ! however you can specify a custom default prefix with the following:
index.js
const DiscordJS = require('discord.js')
const { CommandHandler } = require('advancedhandler')
const client = new DiscordJS.Client()
client.on('ready', () => {
new CommandHandler(client, {
commandsDir: 'commands'
})
.setDefaultPrefix('?')
})
client.login("YOUR TOKEN HERE")
Customizable messages & per-guild languages
AdvancedHandler offers the ability to customize messages as well as translate messages into different languages. Server/guild owners can then specify what language should be used in their server/guild.
Per-guild language configuration
Server owners can use the following command to set what language your bot should used:
!language <language>
Storing custom messages and translations
As the developer you can create a messages.json file that contains your own text and translations. There are two types of objects within this file: direct messages and embeds. Direct messages will be a single message in different languages, while embeds will contain different types of fields. An example of each:
Direct Messages
"COOLDOWN": {
"en": "You must wait {COOLDOWN} before using that command again.",
"tr": "Komutu kullanmadan önce {COOLDOWN} kadar süre beklemelisiniz."
}
Embeds
"HELP": {
"TITLE": {
"en": "Need help? Here are all of my commands:",
"tr": "Yardımamı ihtiyacın var? İşte tüm komutlarım:"
},
"DESCRIPTION": {
"en": "Use {PREFIX}help followed by a command name to get more additional information on a command. For example: \"{PREFIX}help prefix\".",
"tr": "Bir komut hakkında daha fazla bilgi almak için {PREFIX}help ve ardından bir komut adını kullanın. Örneğin: \"{PREFIX}help prefix\"."
}
}
You can find the default messages.json here
You will also need to define where your messages.json file lives in the AdvancedHandler constructor like so:
index.js
new AdvancedHandler.CommandHandler(client, {
commandsDir: 'commands',
messagesPath: 'messages.json'
})
Global syntax errors
In a lot of cases your syntax errors will be very similar. You can specify a global syntax error within your messages.json file like so:
messages.json snippet
"SYNTAX_ERROR": {
"en": "Incorrect usage! Please use \"{PREFIX}{COMMAND} {ARGUMENTS}\"",
"tr": "Yanlış kullanım! Lütfen \"{PREFIX}{COMMAND} {ARGUMENTS}\" kullanın."
}
The {PREFIX}, {COMMAND} and {ARGUMENTS} must always be in upper case. These will be replaced with the correct content when an error occurs. The {ARGUMENTS} variable must be specified in the command like so:
ping.js
ping.js
module.exports = {
minArgs: 1,
maxArgs: -1,
expectedArgs: "<Target user's @>",
callback: ({ message }) => {
message.reply('Pong!')
}
}
A per-command syntax error message will always overwrite a global one for that specific command.
Customizable channel specific commands
Server owners using your bot can set some commands or all to only be ran in specific channels within their server. They can do this with the following:
!channel <enable | disable> <command | all> <tag channel | tag channels>
If a user attempts to use a command in the wrong channel then they will be told what channels they are allowed to use.
Help
Allows users to see which commands the bot has and detailed information about these commands.
If ran !help it show the categories and the all commands. But if ran !help [command] show the commands detail information.
Server stats
It allows users and server/guild owners to see server/guild statistics. There are three types of counters: "all-members", "members" and "bots". This feature can be turned off. They can do this with the following:
!stats <on | off>
Custom events
AdvancedHandler comes with some custom events that help make our lives as developers easier.
databaseConnected Event
This event is fired whenever a database is successfully connected via AdvancedHandler. For more information on how to connect to database please see the "DATABASES" section of this documentation.
index.js
const DiscordJS = require('discord.js')
const { CommandHandler } = require('advancedhandler')
const client = new DiscordJS.Client()
client.on('ready', () => {
const handler = new CommandHandler(client, {
commandsDir: 'commands'
});
handler.on('databaseConnected', (connection, state) => {
console.log('The connection state is "' + state '".');
})
})
client.login("YOUR TOKEN HERE")
commandException Event
This event is fired whenever an exception occurs within one of your commands. You can use this information to log error details or provide a meaningful message to the user.
index.js
const DiscordJS = require('discord.js')
const { CommandHandler } = require('advancedhandler')
const client = new DiscordJS.Client()
client.on('ready', () => {
const handler = new CommandHandler(client, {
commandsDir: 'commands'
});
handler.on('commandException', (command, message, error) => {
console.log(`An exception occured when using command "${command.name}"! The error is:`)
console.error(error) })
})
client.login("YOUR TOKEN HERE")