Skip to content

Commit 320ce5c

Browse files
committed
Initial commit
- With ping, add / remove roles, permission dependent commands
1 parent ef1dcac commit 320ce5c

12 files changed

+546
-0
lines changed

Diff for: .gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,6 @@ dist
128128
.yarn/build-state.yml
129129
.yarn/install-state.gz
130130
.pnp.*
131+
132+
# config file with api keys
133+
config.json

Diff for: commands/utility/double-ping.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Require the SlashCommandBuilder class
2+
const { SlashCommandBuilder } = require('discord.js');
3+
4+
module.exports = {
5+
data: new SlashCommandBuilder()
6+
.setName('double-ping')
7+
.setDescription('Replies with Pong twice'),
8+
async execute(interaction) {
9+
await interaction.reply('pong!');
10+
await interaction.followUp('double pong!');
11+
}
12+
}

Diff for: commands/utility/give-role.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
2+
3+
module.exports = {
4+
data: new SlashCommandBuilder()
5+
.setName('give-role')
6+
.setDescription('Give a user a role.')
7+
.setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles)
8+
9+
// Get input for which user to give role to
10+
.addUserOption(option =>
11+
option.setName('user')
12+
.setDescription('The user to give the role to.')
13+
.setRequired(true))
14+
15+
// Get input for which role to give
16+
.addRoleOption(option =>
17+
option.setName('role')
18+
.setDescription('The role to give to the user.')
19+
.setRequired(true)),
20+
21+
async execute(interaction) {
22+
const guild = interaction.guild;
23+
const member = guild.members.cache.get(interaction.options.getUser('user').id);
24+
const role = interaction.options.getRole('role');
25+
26+
try {
27+
await member.roles.add(role);
28+
await interaction.reply( {content: `The role ${role.name} has been added to ${member.user.username}.`, ephemeral: true } );
29+
} catch (error) {
30+
console.error(error);
31+
await interaction.reply( {content: 'There was an error giving the role.', ephemeral: true } );
32+
}
33+
},
34+
};

Diff for: commands/utility/ping.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Require the SlashCommandBuilder class
2+
const { SlashCommandBuilder } = require('discord.js');
3+
4+
module.exports = {
5+
data: new SlashCommandBuilder()
6+
.setName('ping')
7+
.setDescription('Replies with Pong'),
8+
async execute(interaction) {
9+
await interaction.reply('pong!');
10+
}
11+
}

Diff for: commands/utility/power-level.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Require the SlashCommandBuilder class
2+
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
3+
4+
// This command can only be executed if the user possesses the manage server permission
5+
module.exports = {
6+
data: new SlashCommandBuilder()
7+
.setName('power-level')
8+
.setDescription('Checks your power level')
9+
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild),
10+
async execute(interaction) {
11+
await interaction.reply('over 9000!');
12+
}
13+
}

Diff for: commands/utility/remove-role.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
2+
3+
module.exports = {
4+
data: new SlashCommandBuilder()
5+
.setName('remove-role')
6+
.setDescription('Remove a role from a user.')
7+
.setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles)
8+
9+
// Get input for which user to remove role from
10+
.addUserOption(option =>
11+
option.setName('user')
12+
.setDescription('The user to remove the role from.')
13+
.setRequired(true))
14+
15+
// Get input for which role to remove
16+
.addRoleOption(option =>
17+
option.setName('role')
18+
.setDescription('The role to remove from the user.')
19+
.setRequired(true)),
20+
21+
async execute(interaction) {
22+
const guild = interaction.guild;
23+
const member = guild.members.cache.get(interaction.options.getUser('user').id);
24+
const role = interaction.options.getRole('role');
25+
26+
try {
27+
await member.roles.remove(role);
28+
await interaction.reply( {content: `The role ${role.name} has been removed from ${member.user.username}.`, ephemeral: true } );
29+
} catch (error) {
30+
console.error(error);
31+
await interaction.reply( {content: 'There was an error removing the role.', ephemeral: true } );
32+
}
33+
},
34+
};

Diff for: commands/utility/secret-ping.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Require the SlashCommandBuilder class
2+
const { SlashCommandBuilder } = require('discord.js');
3+
4+
module.exports = {
5+
data: new SlashCommandBuilder()
6+
.setName('secret-ping')
7+
.setDescription('Secretely replies with Pong'),
8+
async execute(interaction) {
9+
// Only the executor of the command can see the response
10+
await interaction.reply({ content: 'secret pong!', ephemeral: true });
11+
}
12+
}

Diff for: commands/utility/user.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Require the SlashCommandBuilder class
2+
const { SlashCommandBuilder } = require('discord.js');
3+
4+
module.exports = {
5+
data: new SlashCommandBuilder()
6+
.setName('user')
7+
.setDescription('Provides information about the user.'),
8+
async execute(interaction) {
9+
// interaction.user is the object representing the User who ran the command
10+
// interaction.member is the GuildMember object, which represents the user in the specific guild
11+
await interaction.reply(`This command was run by ${interaction.user.username}, who joined on ${interaction.member.joinedAt}.`);
12+
},
13+
};

Diff for: deploy_commands.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const { REST, Routes } = require('discord.js');
2+
const { clientId, guildId, token } = require('./config.json');
3+
const fs = require('node:fs');
4+
const path = require('node:path');
5+
6+
const commands = [];
7+
// Grab all the command folders from the commands directory
8+
const foldersPath = path.join(__dirname, 'commands');
9+
const commandFolders = fs.readdirSync(foldersPath);
10+
11+
for (const folder of commandFolders) {
12+
// Grab all the command files from the commands directory
13+
const commandsPath = path.join(foldersPath, folder);
14+
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
15+
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
16+
for (const file of commandFiles) {
17+
const filePath = path.join(commandsPath, file);
18+
const command = require(filePath);
19+
if ('data' in command && 'execute' in command) {
20+
commands.push(command.data.toJSON());
21+
} else {
22+
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
23+
}
24+
}
25+
}
26+
27+
// Construct and prepare an instance of the REST module
28+
const rest = new REST().setToken(token);
29+
30+
// deploy commands
31+
(async () => {
32+
try {
33+
console.log(`Started refreshing ${commands.length} application (/) commands.`);
34+
35+
// The put method is used to fully refresh all commands in the guild with the current set
36+
const data = await rest.put(
37+
Routes.applicationGuildCommands(clientId, guildId),
38+
// change above to Routes.applicationCommands(clientId) to make commands global
39+
{ body: commands },
40+
);
41+
42+
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
43+
} catch (error) {
44+
// catch and log any errors
45+
console.error(error);
46+
}
47+
})();

Diff for: index.js

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
const fs = require('node:fs'); // Node file system module, used to read `commands` directory
2+
const path = require('node:path'); // Node path utility module, helps to construct paths to access files
3+
4+
// Require discord.js classes and bot token
5+
const { Client, Collection, Events, GatewayIntentBits } = require('discord.js');
6+
const { token } = require('./config.json');
7+
8+
// Create the client instance
9+
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
10+
client.commands = new Collection();
11+
12+
// Get the path to the commands folder and gets an array of all folders inside
13+
const foldersPath = path.join(__dirname, 'commands');
14+
const commandFolders = fs.readdirSync(foldersPath);
15+
16+
// Loop through all of the folders in commandFolders
17+
for (const folder of commandFolders) {
18+
19+
// Construct the path and read the filenames in the folder into commandFiles
20+
const commandsPath = path.join(foldersPath, folder);
21+
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); // Remove non js files
22+
23+
// Loop through each file in the folder
24+
for (const file of commandFiles) {
25+
// Construct the file path and read the file
26+
const filePath = path.join(commandsPath, file);
27+
const command = require(filePath);
28+
29+
// Set a new item in the Collection with the key as the command name and the value as the exported module
30+
if ('data' in command && 'execute' in command) {
31+
client.commands.set(command.data.name, command);
32+
} else {
33+
// Make sure empty or incomplete commands aren't loaded
34+
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
35+
}
36+
}
37+
}
38+
39+
// Create a listener for events to execute when an interaction is received
40+
client.on(Events.InteractionCreate, async interaction => {
41+
// Ensure only slash commands are handled
42+
if (!interaction.isChatInputCommand()) return;
43+
44+
// Get the command matching the command name, exit if none is found
45+
const command = interaction.client.commands.get(interaction.commandName);
46+
if(!command) {
47+
console.error(`No command matching ${interaction.commandName} was found :(`);
48+
return;
49+
}
50+
51+
// Try to execute the command
52+
try {
53+
await command.execute(interaction);
54+
} catch (error) {
55+
console.error(error);
56+
if (interaction.replied || interaction.deferred) {
57+
await interaction.followUp({ content: 'There was an error while executing this command!', ephemeral: true });
58+
} else {
59+
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
60+
}
61+
}
62+
});
63+
64+
// When the client is ready, run this code once
65+
client.once(Events.ClientReady, readyClient => {
66+
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
67+
});
68+
69+
client.login(token)

0 commit comments

Comments
 (0)