Skip to content

Commit

Permalink
Initial update to v13
Browse files Browse the repository at this point in the history
Updated everything
  • Loading branch information
YorkAARGH committed Jul 7, 2021
1 parent 12bdfaf commit b4905d8
Show file tree
Hide file tree
Showing 23 changed files with 4,100 additions and 141 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"parserOptions": {
"ecmaVersion": 2020
"ecmaVersion": 2021
},
"env": {
"es6": true,
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ typings/
# dotenv environment variables file
.env

/.vscode/
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Guide Bot

An example of a Discord.js Bot Handler. Updated and Maintained by the Idiot's Guide Community.

Ages ago, Guide Bot was actually a little bot I had on the official discord.js server.
It helped me link to the d.js bot making guide I was building, with links.
This bot grew into something that I could show new coders and bot makers, but
over time it grew into a full framework - one that is now under the hands of a
over time it grew into a full framework - one that is now under the hands of a
group of contributors, and no longer easily "understandable" by the majority
of our newbies. So I've pulled the original Guide Bot out of the mothballs,
gave it a fresh coat of paint and grease, and here it is back in its full glory!
Expand All @@ -16,30 +17,30 @@ gave it a fresh coat of paint and grease, and here it is back in its full glory!
- The node-gyp build tools. This is a pre-requisite for Enmap, but also for a **lot** of other modules. See [The Enmap Guide](https://enmap.evie.codes/install#pre-requisites) for details and requirements for your OS. Just follow what's in the tabbed block only, then come back here!

You also need your bot's token. This is obtained by creating an application in
the [Developer section](https://discord.com/developers) of discord.com. Check the [first section of this page](https://anidiots.guide/getting-started/the-long-version.html)
for more info.
the [Developer section](https://discord.com/developers) of discord.com. Check the [first section of this page](https://anidiots.guide/getting-started/the-long-version.html) for more info.

## Intents

Guidebot uses intents which are required as of October 7, 2020.
You can enable privileged intents in your bot page
Guidebot uses intents which are required as of October 7, 2020.
You can enable privileged intents in your bot page
(the one you got your token from) under `Privileged Gateway Intents`.

By default GuideBot needs the Guilds, Guild Messages and Direct Messages intents to work.
For join messages to work you need Guild Members, which is privileged.
User counts that GuideBot has in places such as in the ready log, and the stats
User counts that GuideBot has in places such as in the ready log, and the stats
command may be incorrect without the Guild Members intent.

Intents are loaded from your config, and will get created by the setup scripts.

For more info about intents checkout the [official Discord.js guide page](https://discordjs.guide/popular-topics/intents.html) and the [official Discord docs page](https://discord.com/developers/docs/topics/gateway#gateway-intents).

## Downloading

In a command prompt in your projects folder (wherever that may be) run the following:

`git clone https://github.com/An-Idiots-Guide/guidebot.git`

Once finished:
Once finished:

- In the folder from where you ran the git command, run `cd guidebot` and then run `npm install`
- **If you get any error about python or msibuild.exe or binding, read the requirements section again!**
Expand All @@ -53,7 +54,7 @@ To start the bot, in the command prompt, run the following command:

## Inviting to a guild

To add the bot to your guild, you have to get an oauth link for it.
To add the bot to your guild, you have to get an oauth link for it.

You can use this site to help you generate a full OAuth Link, which includes a calculator for the permissions:
[https://finitereality.github.io/permissions-calculator/?v=0](https://finitereality.github.io/permissions-calculator/?v=0)
46 changes: 25 additions & 21 deletions commands/conf.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const { inspect } = require("util");

/*
FOR GUILD SETTINGS SEE set.js !
This command is used to modify the bot's default configuration values, which affects all guilds.
Expand All @@ -12,38 +10,39 @@ exports.run = async (client, message, [action, key, ...value], level) => { // es

// Retrieve Default Values from the default settings in the bot.
const defaults = client.settings.get("default");

const replying = client.settings.get(message.guild.id).commandReply;

// Adding a new key adds it to every guild (it will be visible to all of them)
if (action === "add") {
if (!key) return message.reply("Please specify a key to add");
if (defaults[key]) return message.reply("This key already exists in the default settings");
if (value.length < 1) return message.reply("Please specify a value");
if (!key) return message.reply({ content: "Please specify a key to add", allowedMentions: { repliedUser: (replying === "true") }});
if (defaults[key]) return message.reply({ content: "This key already exists in the default settings", allowedMentions: { repliedUser: (replying === "true") }});
if (value.length < 1) return message.reply({ content: "Please specify a value", allowedMentions: { repliedUser: (replying === "true") }});

// `value` being an array, we need to join it first.
defaults[key] = value.join(" ");

// One the settings is modified, we write it back to the collection
client.settings.set("default", defaults);
message.reply(`${key} successfully added with the value of ${value.join(" ")}`);
message.reply({ content: `${key} successfully added with the value of ${value.join(" ")}`, allowedMentions: { repliedUser: (replying === "true") }});
} else

// Changing the default value of a key only modified it for guilds that did not change it to another value.
if (action === "edit") {
if (!key) return message.reply("Please specify a key to edit");
if (!defaults[key]) return message.reply("This key does not exist in the settings");
if (value.length < 1) return message.reply("Please specify a new value");
if (!key) return message.reply({ content: "Please specify a key to edit", allowedMentions: { repliedUser: (replying === "true") }});
if (!defaults[key]) return message.reply({ content: "This key does not exist in the settings", allowedMentions: { repliedUser: (replying === "true") }});
if (value.length < 1) return message.reply({ content: "Please specify a new value", allowedMentions: { repliedUser: (replying === "true") }});

defaults[key] = value.join(" ");

client.settings.set("default", defaults);
message.reply(`${key} successfully edited to ${value.join(" ")}`);
message.reply({ content: `${key} successfully edited to ${value.join(" ")}`, allowedMentions: { repliedUser: (replying === "true") }});
} else

// WARNING: DELETING A KEY FROM THE DEFAULTS ALSO REMOVES IT FROM EVERY GUILD
// MAKE SURE THAT KEY IS REALLY NO LONGER NEEDED!
if (action === "del") {
if (!key) return message.reply("Please specify a key to delete.");
if (!defaults[key]) return message.reply("This key does not exist in the settings");
if (!key) return message.reply({ content: "Please specify a key to delete.", allowedMentions: { repliedUser: (replying === "true") }});
if (!defaults[key]) return message.reply({ content: "This key does not exist in the settings", allowedMentions: { repliedUser: (replying === "true") }});

// Throw the 'are you sure?' text at them.
const response = await client.awaitReply(message, `Are you sure you want to permanently delete ${key} from all guilds? This **CANNOT** be undone.`);
Expand All @@ -57,28 +56,33 @@ exports.run = async (client, message, [action, key, ...value], level) => { // es

// then we loop on all the guilds and remove this key if it exists.
// "if it exists" is done with the filter (if the key is present and it's not the default config!)
for (const [guildid, conf] of client.settings.filter((setting, id) => setting[key] && id !== "default")) {
for (const [guildId, conf] of client.settings.filter((setting, id) => setting[key] && id !== "default")) {
delete conf[key];
client.settings.set(guildid, conf);
client.settings.set(guildId, conf);
}

message.reply(`${key} was successfully deleted.`);
message.reply({ content: `${key} was successfully deleted.`, allowedMentions: { repliedUser: (replying === "true") }});
} else
// If they respond with n or no, we inform them that the action has been cancelled.
if (["n","no","cancel"].includes(response)) {
message.reply("Action cancelled.");
message.reply({ content: "Action cancelled.", allowedMentions: { repliedUser: (replying === "true") }});
}
} else

// Display a key's default value
if (action === "get") {
if (!key) return message.reply("Please specify a key to view");
if (!defaults[key]) return message.reply("This key does not exist in the settings");
message.reply(`The value of ${key} is currently ${defaults[key]}`);
if (!key) return message.reply({ content: "Please specify a key to view", allowedMentions: { repliedUser: (replying === "true") }});
if (!defaults[key]) return message.reply({ content: "This key does not exist in the settings", allowedMentions: { repliedUser: (replying === "true") }});
message.reply({ content: `The value of ${key} is currently ${defaults[key]}`, allowedMentions: { repliedUser: (replying === "true") }});

// Display all default settings.
} else {
await message.channel.send(`***__Bot Default Settings__***\n\`\`\`json\n${inspect(defaults)}\n\`\`\``);
const array = [];
Object.entries(client.settings.get("default")).forEach(([key, value]) => {
array.push(`${key}${" ".repeat(20 - key.length)}:: ${value}`);
});
await message.channel.send(`\`\`\`asciidoc\n= Bot Default Settings =
${array.join("\n")}\`\`\``);
}
};

Expand Down
6 changes: 3 additions & 3 deletions commands/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ exports.run = (client, message, args, level) => {
const longest = commandNames.reduce((long, str) => Math.max(long, str.length), 0);

let currentCategory = "";
let output = `= Command List =\n\n[Use ${message.settings.prefix}help <commandname> for details]\n`;
let output = `\`\`\`asciidoc\n= Command List =\n\n[Use ${message.settings.prefix}help <commandname> for details]\n`;
const sorted = myCommands.array().sort((p, c) => p.help.category > c.help.category ? 1 : p.help.name > c.help.name && p.help.category === c.help.category ? 1 : -1 );
sorted.forEach( c => {
const cat = c.help.category.toProperCase();
Expand All @@ -28,14 +28,14 @@ exports.run = (client, message, args, level) => {
}
output += `${message.settings.prefix}${c.help.name}${" ".repeat(longest - c.help.name.length)} :: ${c.help.description}\n`;
});
message.channel.send(output, {code: "asciidoc", split: { char: "\u200b" }});
message.channel.send(output + "\n```");
} else {
// Show individual command's help.
let command = args[0];
if (client.commands.has(command)) {
command = client.commands.get(command);
if (level < client.levelCache[command.conf.permLevel]) return;
message.channel.send(`= ${command.help.name} = \n${command.help.description}\nusage:: ${command.help.usage}\naliases:: ${command.conf.aliases.join(", ")}\n= ${command.help.name} =`, {code:"asciidoc"});
message.channel.send(`\`\`\`asciidoc\n= ${command.help.name} = \n${command.help.description}\nusage:: ${command.help.usage}\naliases:: ${command.conf.aliases.join(", ")}\n= ${command.help.name} =\`\`\``);
}
}
};
Expand Down
5 changes: 3 additions & 2 deletions commands/mylevel.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
exports.run = async (client, message, args, level) => {
const friendly = client.config.permLevels.find(l => l.level === level).name;
message.reply(`Your permission level is: ${level} - ${friendly}`);
const replying = client.settings.get(message.guild.id).commandReply;
message.reply({ content: `Your permission level is: ${level} - ${friendly}`, allowedMentions: { repliedUser: (replying === "true") }});
};

exports.conf = {
Expand All @@ -12,7 +13,7 @@ exports.conf = {

exports.help = {
name: "mylevel",
category: "Miscelaneous",
category: "Miscellaneous",
description: "Tells you your permission level for the current message location.",
usage: "mylevel"
};
2 changes: 1 addition & 1 deletion commands/ping.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exports.conf = {

exports.help = {
name: "ping",
category: "Miscelaneous",
category: "Miscellaneous",
description: "It like... Pings. Then Pongs. And it's not Ping Pong.",
usage: "ping"
};
3 changes: 2 additions & 1 deletion commands/reboot.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
exports.run = async (client, message, args, level) => { // eslint-disable-line no-unused-vars
await message.reply("Bot is shutting down.");
const replying = client.settings.get(message.guild.id).commandReply;
await message.reply({ content: "Bot is shutting down.", allowedMentions: { repliedUser: (replying === "true") }});
await Promise.all(client.commands.map(cmd =>
client.unloadCommand(cmd)
));
Expand Down
9 changes: 5 additions & 4 deletions commands/reload.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
exports.run = async (client, message, args, level) => { // eslint-disable-line no-unused-vars
if (!args || args.length < 1) return message.reply("Must provide a command to reload. Derp.");
const replying = client.settings.get(message.guild.id).commandReply;
if (!args || args.length < 1) return message.reply({ content: "Must provide a command to reload. Derp.", allowedMentions: { repliedUser: (replying === "true") }});
const command = client.commands.get(args[0]) || client.commands.get(client.aliases.get(args[0]));
let response = await client.unloadCommand(args[0]);
if (response) return message.reply(`Error Unloading: ${response}`);
if (response) return message.reply({ content: `Error Unloading: ${response}`, allowedMentions: { repliedUser: (replying === "true") }});

response = client.loadCommand(command.help.name);
if (response) return message.reply(`Error Loading: ${response}`);
if (response) return message.reply({ content: `Error Loading: ${response}`, allowedMentions: { repliedUser: (replying === "true") }});

message.reply(`The command \`${command.help.name}\` has been reloaded`);
message.reply({ content: `The command \`${command.help.name}\` has been reloaded`, allowedMentions: { repliedUser: (replying === "true") }});
};

exports.conf = {
Expand Down
30 changes: 16 additions & 14 deletions commands/set.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,20 @@ exports.run = async (client, message, [action, key, ...value], level) => { // es
const settings = message.settings;
const defaults = client.settings.get("default");
const overrides = client.settings.get(message.guild.id);
const replying = settings.commandReply;
if (!client.settings.has(message.guild.id)) client.settings.set(message.guild.id, {});

// Edit an existing key value
if (action === "edit") {
// User must specify a key.
if (!key) return message.reply("Please specify a key to edit");
if (!key) return message.reply({ content: "Please specify a key to edit", allowedMentions: { repliedUser: (replying === "true") }});
// User must specify a key that actually exists!
if (!defaults[key]) return message.reply("This key does not exist in the settings");
if (!defaults[key]) return message.reply({ content: "This key does not exist in the settings", allowedMentions: { repliedUser: (replying === "true") }});
const joinedValue = value.join(" ");
// User must specify a value to change.
if (joinedValue.length < 1) return message.reply("Please specify a new value");
if (joinedValue.length < 1) return message.reply({ content: "Please specify a new value", allowedMentions: { repliedUser: (replying === "true") }});
// User must specify a different value than the current one.
if (joinedValue === settings[key]) return message.reply("This setting already has that value!");
if (joinedValue === settings[key]) return message.reply({ content: "This setting already has that value!", allowedMentions: { repliedUser: (replying === "true") }});

// If the guild does not have any overrides, initialize it.
if (!client.settings.has(message.guild.id)) client.settings.set(message.guild.id, {});
Expand All @@ -37,14 +38,14 @@ exports.run = async (client, message, [action, key, ...value], level) => { // es
client.settings.set(message.guild.id, joinedValue, key);

// Confirm everything is fine!
message.reply(`${key} successfully edited to ${joinedValue}`);
message.reply({ content: `${key} successfully edited to ${joinedValue}`, allowedMentions: { repliedUser: (replying === "true") }});
} else

// Resets a key to the default value
if (action === "del" || action === "reset") {
if (!key) return message.reply("Please specify a key to reset.");
if (!defaults[key]) return message.reply("This key does not exist in the settings");
if (!overrides[key]) return message.reply("This key does not have an override and is already using defaults.");
if (!key) return message.reply({ content: "Please specify a key to reset.", allowedMentions: { repliedUser: (replying === "true") }});
if (!defaults[key]) return message.reply({ content: "This key does not exist in the settings", allowedMentions: { repliedUser: (replying === "true") }});
if (!overrides[key]) return message.reply({ content: "This key does not have an override and is already using defaults.", allowedMentions: { repliedUser: (replying === "true") }});

// Good demonstration of the custom awaitReply method in `./modules/functions.js` !
const response = await client.awaitReply(message, `Are you sure you want to reset ${key} to the default value?`);
Expand All @@ -53,26 +54,27 @@ exports.run = async (client, message, [action, key, ...value], level) => { // es
if (["y", "yes"].includes(response.toLowerCase())) {
// We delete the `key` here.
client.settings.delete(message.guild.id, key);
message.reply(`${key} was successfully reset to default.`);
message.reply({ content: `${key} was successfully reset to default.`, allowedMentions: { repliedUser: (replying === "true") }});
} else
// If they respond with n or no, we inform them that the action has been cancelled.
if (["n","no","cancel"].includes(response)) {
message.reply(`Your setting for \`${key}\` remains at \`${settings[key]}\``);
message.reply({ content: `Your setting for \`${key}\` remains at \`${settings[key]}\``, allowedMentions: { repliedUser: (replying === "true") }});
}
} else

if (action === "get") {
if (!key) return message.reply("Please specify a key to view");
if (!defaults[key]) return message.reply("This key does not exist in the settings");
if (!key) return message.reply({ content: "Please specify a key to view", allowedMentions: { repliedUser: (replying === "true") }});
if (!defaults[key]) return message.reply({ content: "This key does not exist in the settings", allowedMentions: { repliedUser: (replying === "true") }});
const isDefault = !overrides[key] ? "\nThis is the default global default value." : "";
message.reply(`The value of ${key} is currently ${settings[key]}${isDefault}`);
message.reply({ content: `The value of ${key} is currently ${settings[key]}${isDefault}`, allowedMentions: { repliedUser: (replying === "true") }});
} else {
// Otherwise, the default action is to return the whole configuration;
const array = [];
Object.entries(settings).forEach(([key, value]) => {
array.push(`${key}${" ".repeat(20 - key.length)}:: ${value}`);
});
await message.channel.send(`= Current Guild Settings =\n${array.join("\n")}`, {code: "asciidoc"});
await message.channel.send(`\`\`\`asciidoc\n= Current Guild Settings =
${array.join("\n")}\`\`\``);
}
};

Expand Down
Loading

0 comments on commit b4905d8

Please sign in to comment.