Advanced all-in-one discord bot with prefix & slash commands
With over 100 slash command and over 50 prefix commands, Testify is an open source discord bot that's easy to set up and use and full of fun features to use for your servers!
To test out Testify, be sure to invite him to your server by clicking here
β If your a fan of this repository or have used it or any of it's code, please consider leaving us a star. It would be greatly appreciated and allows us to see if users value the bot! β
- Download Node.js.
- Download Visual Studio Code.
-
Project Setup
-
Fork the Github project :
-
Click the
Code
button. From the drop-down that appears, clickDownload ZIP
to download the entire repository as a ZIP folder. -
Extract the files to a new folder and open it with Visual Studio Code.
-
-
Obtain Discord Bot Token
-
Sign in to Discord Developer Portal.
-
Create a bot :
- Enter the left side
Applications
. - Click
New Application
in the upper right corner and enter the name of the bot. After confirmation, enter the new page. - Click on the left side
Bot
. - Enable all intents listed under
Privileged Gateway Intents
and clickSave Changes
. - View and copy the token by clicking the
Reset Token
button.
- Enter the left side
-
Set up OAuth2 :
- Click on
OAuth2
in the left column. - Click on
URL Generator
in the left column. - In the right column, select
bot
andapplications.commands
underSCOPES
. - Scroll down and select
Administrator
underBOT PERMISSIONS
. - Copy the URL at the bottom and paste it into your browser.
- Choose the server you want to add the bot to and click
Continue
>Authorize
.
- Click on
-
-
Obtain MongoDB Connection String
- Sign up / Sign in to MongoDB.
- Choose your preferred cloud database plan.
- Customize the cluster settings to your preference and click
Create Cluster
. - Navigate to the
Network Access
page, clickAdd IP Address
and selectAllow access from anywhere
. - Navigate back to the
Database
page and clickConnect
. - Create a
database user
, clickChoose a connection method
and selectConnect your application
. - Copy your connection string and replace
<password>
with the password for the database user that you created earlier.
-
Setting up the env file
If you go along with this, you can ignore the parts in the
Project Execution
that explain how to generate and fill in the.env
- For easy setup of the env files, (
.env
&.development.env
) you can run the commandnpm run setup-env:prod
- Once you've ran the command, it generates a script in the console
- You need to then fill out the fields in the console. Fields marked with the text "Required" are you required fields and you need to fill those ones in. The script will not continue if you ignore to fill in those fields.
- Once you've filled in the field, it will write those fields into and generate the
.env
. - Alternatively, you can ignore this and fill in the fields yourself by viewing the
.example.env
file. - If you then want to setup the
.env.development
file, you can run the commandnpm run setup-env:dev
and follow the steps above again.
- For easy setup of the env files, (
-
Project Execution
- Rename the filed named
example.env
to.env
- Navigate to the
Bot
page on the Discord Developer Portal and clickReset Token
. Afterwards, create a.env
file within the root directory. - Paste your bot token into the
token
variable inside the.env
file. - Paste your MongoDB connection string into the
mongodb
variable inside the.env
file. - Navigate to the
OAuth2
page and copy theCLIENT ID
. - Paste your client ID into the
clientid
variable inside the.env
file. - Navigate to your discord server, enable developer mode and right click the dropdown beside the server name.
- Click
Copy Server ID
and paste it into theguildid
variable inside the.env
file. - Navigate to the
package.json
file and pay attention to the runnable commands listed underscripts
. - Open the terminal in Visual Studio Code and install all necessary packages using
npm run setup
. This will install the dependencies and give you a brief install guide - Open a new terminal and type
npm run prod
to run the file without using nodemon ornpm run prod:nodemon
to run the bot with nodemon. - The bot should then turn online, you should be able to see this by the console logs that is setup upon start up
- Rename the filed named
-
Runnable commands (scripts)
Wipe Database -
To wipe the database that is connected via your mongoDB url, you can run the commandnpm run wipe-data:prod
, this brings up a menu which you can follow in order to either wipe the entire database from all it's data, or wipe all the data from individual schemas.Update Packages -
To update all your dependencies, you can run the commandnpm run update-packages
, this cycles through the dependencies and updates one's which are out of date.update-ytdl-core -
To update the version of theytdl-core
package, you can run the commandnpm run update-ytdl-core
, this updates the package to the most recent version to ensure the music system works.setup-env:prod -
To run the setup of the.env
file you can run the commandnpm run setup-env:prod
, this generates a script in the console that generates a.env
file and where you fill out the fields with whats required for the.env
file and it writes it in the file.setup-env:dev -
To run the setup of the.env.development
file you can run the commandnpm run setup-env:dev
, this generates a script in the console that generates a.env.development
file and where you fill out the fields with whats required for the.env.development
file and it writes it in the file.
To set the advanced logs registry for the Testify audit-logs ( the event handler registers ) than follow this!
- Navigate to
node_modules
=>discord-logs
=>lib
=>index.js
- Once in the
index.js
file for the discord logs package you'll want to copy and paste this code in below.
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const color = {
red: '\x1b[31m',
orange: '\x1b[38;5;202m',
yellow: '\x1b[33m',
green: '\x1b[32m',
blue: '\x1b[34m',
reset: '\x1b[0m',
pink: '\x1b[38;5;213m'
}
function getTimestamp() {
const date = new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
const discord_js_1 = require("discord.js");
const handlers_1 = require("./handlers");
let eventRegistered = false;
module.exports = (client, options) => __awaiter(void 0, void 0, void 0, function* () {
if (eventRegistered)
return;
eventRegistered = true;
const intents = new discord_js_1.IntentsBitField(client.options.intents);
/* HANDLE GUILDS EVENTS */
if (intents.has(discord_js_1.IntentsBitField.Flags.Guilds)) {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`${color.pink}[${getTimestamp()}] ${color.reset}[AUDIT_LOGS] ChannelUpdate event handler registered.`);
client.on('channelUpdate', (oldChannel, newChannel) => {
(0, handlers_1.handleChannelUpdateEvent)(client, oldChannel, newChannel);
});
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`${color.pink}[${getTimestamp()}] ${color.reset}[AUDIT_LOGS] GuildUpdate event handler registered.`);
client.on('guildUpdate', (oldGuild, newGuild) => {
(0, handlers_1.handleGuildUpdateEvent)(client, oldGuild, newGuild);
});
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`${color.pink}[${getTimestamp()}] ${color.reset}[AUDIT_LOGS] RoleUpdate event handler registered.`);
client.on('roleUpdate', (oldRole, newRole) => {
(0, handlers_1.handleRoleUpdateEvent)(client, oldRole, newRole);
});
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`${color.pink}[${getTimestamp()}] ${color.reset}[AUDIT_LOGS] ThreadUpdate event handler registered.`);
client.on('threadUpdate', (oldThread, newThread) => {
(0, handlers_1.handleThreadChannelUpdateEvent)(client, oldThread, newThread);
});
}
else {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`channelUpdate, guildUpdate, roleUpdate and threadUpdate event handlers not registered (missing Guilds intent).`);
}
/* HANDLE MEMBER EVENTS */
if (intents.has(discord_js_1.IntentsBitField.Flags.GuildMembers)) {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`${color.pink}[${getTimestamp()}] ${color.reset}[AUDIT_LOGS] GuildMemberUpdate event handler registered.`);
client.on('guildMemberUpdate', (oldMember, newMember) => {
(0, handlers_1.handleGuildMemberUpdateEvent)(client, oldMember, newMember);
});
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`${color.pink}[${getTimestamp()}] ${color.reset}[AUDIT_LOGS] UserUpdate event handler registered.`);
client.on('userUpdate', (oldUser, newUser) => {
(0, handlers_1.handleUserUpdateEvent)(client, oldUser, newUser);
});
}
else {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log('guildMemberUpdate, userUpdate event handlers not registered (missing GuildMembers intent).');
}
/* HANDLE MESSAGE UPDATE EVENTS */
if (intents.has(discord_js_1.IntentsBitField.Flags.GuildMessages && discord_js_1.IntentsBitField.Flags.MessageContent)) {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`${color.pink}[${getTimestamp()}] ${color.reset}[AUDIT_LOGS] MessageUpdate event handler registered.`);
client.on('messageUpdate', (oldMessage, newMessage) => {
(0, handlers_1.handleMessageUpdateEvent)(client, oldMessage, newMessage);
});
}
else {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log('messageUpdate event handler not registered (missing GuildMessages or MessageContent intent).');
}
/* HANDLE PRESENCE UPDATE EVENTS */
if (intents.has(discord_js_1.IntentsBitField.Flags.GuildPresences)) {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`${color.pink}[${getTimestamp()}] ${color.reset}[AUDIT_LOGS] PresenceUpdate event handler registered.`);
client.on('presenceUpdate', (oldPresence, newPresence) => {
(0, handlers_1.handlePresenceUpdateEvent)(client, oldPresence, newPresence);
});
}
else {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log('presenceUpdate event handler not registered (missing GuildPresences intent).');
}
/* HANDLE VOICE STATE UPDATE */
if (intents.has(discord_js_1.IntentsBitField.Flags.GuildVoiceStates)) {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log(`${color.pink}[${getTimestamp()}] ${color.reset}[AUDIT_LOGS] VoiceStateUpdate event handler registered.`);
client.on('voiceStateUpdate', (oldState, newState) => {
(0, handlers_1.handleVoiceStateUpdateEvent)(client, oldState, newState);
});
}
else {
if (options === null || options === void 0 ? void 0 : options.debug)
console.log('voiceStateUpdate event handler not registered (missing GuildVoiceStates intent).');
}
});
- This code makes the logs register like so this image below
- To update the color of the logs, you can change the part
${color.pink}
to the color you'd like which are defined in the color variable. - That should be it, now when you start up the bot, it should look all cool π
Connect with us on Discord for support / any related inquiry.
Released under the terms of MIT License license.
Thanks to TheLegendDev for the readme template from Nub Bot π