Skip to content

Commit

Permalink
Interactions
Browse files Browse the repository at this point in the history
  • Loading branch information
J-Human authored Jun 18, 2021
2 parents 6753b88 + abe159e commit 1c3d78a
Show file tree
Hide file tree
Showing 12 changed files with 320 additions and 8 deletions.
37 changes: 34 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# NoStickers-Discord-Bot
![NoStickers-Discord-Bot](https://socialify.git.ci/MrCrypticXDev/NoStickers-Discord-Bot/image?description=1&forks=1&issues=1&language=1&logo=https%3A%2F%2Fim-an.explorer.workers.dev%2FPgaUZal.png&owner=1&pattern=Circuit%20Board&pulls=1&stargazers=1&theme=Light)
[![ESLint](https://github.com/MrCrypticXDev/NoStickers-Discord-Bot/actions/workflows/lint.yml/badge.svg)](https://github.com/MrCrypticXDev/NoStickers-Discord-Bot/actions/workflows/lint.yml) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.0-4baaaa.svg)](.github/CODE_OF_CONDUCT.md)

## About
The source code for the NoStickers bot that uses Discord.js. It also has an added-on customizable tweaks/configs for server admins. 👀

Expand All @@ -27,13 +28,43 @@ So now you have a copy, follow the steps below:
* `YOUR_USER_ID` refers to your user ID on Discord. There's an [article](https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-) for that.
* `YOUR_BOT_PREFIX` refers to the character your bot will detect for, so that it knows when to respond to a command. For example, `!`.
* `YOUR_MONGODB_URL` refers to the URL of your MongoDB cluster.
4. Run `node src/index.js` to start the bot. Don't forget to invite it!
5. And lastly, **enjoy Stickers while you can.** 🌺
* `YOUR_APP_PUBLIC_KEY` refers to the public key retrieved from your app in the developer portal. This appears in the general page, just below the app ID.

4. You'll have to register the slash commands. Don't worry, we got your back, so just follow the next bullet points:
* Feel free to create a file (perhaps `create-slash-commands.js`).
* Stick this following piece of code:

```js
const fetch = require('node-fetch');

const token = '';
const id = '';

const json = [{ name: 'eval', description: 'Executes the given code', options: [{ name: 'code', description: 'The code to evaluate', type: 3, required: true }] }, { name: 'help', description: 'Shows the help embed' }, { name: 'invite', description: 'The link for inviting the bot' }, { name: 'stickers', description: 'Allows stickers in the given channel', options: [{ name: 'channel', description: 'The channel to allow sending of stickers from', type: 7, required: true }] }, { name: 'nosticker', description: 'Deletes stickers in the given channel', options: [{ name: 'channel', description: 'The channel to disable usage of stickers from', type: 7, required: true }] }];

for (const i of json) {
fetch(`https://discord.com/api/applications/${id}/commands`, {
method: 'POST',
headers: {
'Authorization': `Bot ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(i)
})
.then(res => res.json())
.then(data => console.log(data));
}
```
* Run `node create-slash-commands.js`. Make sure to have node-fetch installed, as well as the details placed in the variables. If you see an output of JSON in your console without any error messages, you're good to go!
* Now you'll actually have to allow your bot to receive interactions. To do that, go to your app's homepage, navigate to the interactions endpoint URL field and place the link + the `/interactions` endpoint (e.g. `https://bot.site/interactions`). Keep in mind you'll need the server running.

5. Run `node src/index.js` to start the bot. Don't forget to invite it!
6. And lastly, **enjoy Stickers while you can.** 🌺

## Additional information
* You may run `npm run lint` to find errors in your code. There's also `npm run lint:fix` that has the ability to correct certain types of mistakes.
* Written in the JavaScript language, runs on the Node.js runtime environment, and uses Discord.js as the core library.
* Chalk is used for logging, whilst mongoose is for using MongoDB. ESLint is for code linting.
* Chalk is used for logging, whilst mongoose is for using MongoDB. ESLint is for code linting. There are also other libraries used such as discord-interactions and node-fetch for creating and replying to slash commands and interactions.

## License
The NoStickers Discord bot is released under the GNU General Public License 3.0. See [LICENSE](LICENSE) for more details.
Expand Down
15 changes: 14 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "NoStickers-Structures",
"version": "1.1.0",
"version": "1.2.0",
"description": "The Source Code for NoStickers bot written in Discord.js also added on customizable tweaks/configs for server admins. 👀",
"main": "./src/index.js",
"scripts": {
Expand All @@ -25,6 +25,7 @@
"dependencies": {
"chalk": "^4.1.1",
"discord.js": "^12.5.3",
"discord-interactions": "^2.3.0",
"mongoose": "^5.12.13"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/invite.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class inviteCommand {
*/
// eslint-disable-next-line no-unused-vars
async main(client, message, args) {
return message.channel.send(`https://discord.com/oauth2/authorize?client_id=${client.user.id}&scope=bot&permissions=338944`);
return message.channel.send(`https://discord.com/oauth2/authorize?client_id=${client.user.id}&scope=bot+applications.commands&permissions=338944`);
}
}

Expand Down
47 changes: 47 additions & 0 deletions src/Interactions/eval.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const util = require('util');

/**
* Execute the given code
* @param {client} client Discord.js client instance
* @param {Object} request Express.js request payload
* @param {response} response The response to send back
* @returns {void}
*/
module.exports = (client, request, response) => {
const interaction = request.body;
const args = interaction.data.options;

if (!client.config.ownerIDs.includes(interaction.member.user.id || interaction.member.user.id)) {
return response.send({
type: 4,
data: {
content: 'Unfortunately, you cannot use this command.',
flags: 64
}
});
}

try {
const code = args.find(option => option.name === 'code').value == '-a' ? args.find(option => option.name === 'code').value.slice(1).join(' ') : args.find(option => option.name === 'code').value.join(' ');

const fullCode = args[0].toLowerCase() == '-a' ? '(async () => {\n{code}\n})()': '{code}';
const str = fullCode.replace('{code}', code);
const evaluation = util.inspect(eval(str), {
depth: 0,
});

return response.send({
type: 4,
data: {
content: `\`\`\`js\n${evaluation}\`\`\``
}
}).catch(console.error);
} catch (e) {
return response.send({
type: 4,
data: {
content: `\`\`\`js\n${e.message}\`\`\``
}
}).catch(console.error);
}
};
34 changes: 34 additions & 0 deletions src/Interactions/help.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Shows the help embed
* @param {client} client Discord.js client instance
* @param {Object} request Express.js request payload
* @param {response} response The response to send back
* @returns {void}
*/
module.exports = (client, request, response) => {
const interaction = request.body;

response.send({
type: 4,
data: {
embeds: [{
author: {
name: 'NoStickers\' Help Menu',
icon_url: client.user.avatarURL()
},
color: [240, 71, 71],
description: `
\`help\` - Shows the list of commands.
\`invite\` - Invite me to your server.
\`nostickers\` - Disables stickers for the specific channels.
\`stickers\` - Enables stickers for the specific channels.
`,
footer: {
text: `Requested by ${interaction.member.user.username + '#' + interaction.member.user.discriminator || interaction.user.username + '#' + interaction.user.discriminator}`,
icon_url: `https://cdn.discordapp.com/avatars/${interaction.member.user.id || interaction.user.id}/${interaction.member.user.avatar || interaction.user.avatar}.gif`,
timestamp: Date.now()
}
}]
}
});
};
15 changes: 15 additions & 0 deletions src/Interactions/invite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* The link for inviting the bot
* @param {client} client Discord.js client instance
* @param {Object} request Express.js request payload
* @param {response} response The response to send back
* @returns {void}
*/
module.exports = (client, request, response) => {
response.send({
type: 4,
data: {
content: `https://discord.com/oauth2/authorize?client_id=${client.user.id}&scope=bot+applications.commands&permissions=338944`
}
});
};
65 changes: 65 additions & 0 deletions src/Interactions/nosticker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const Guild = require('../Models/Guild.js');

/**
* Delete stickers in the specified channel(s)
* @param {client} client Discord.js client instance
* @param {Object} request Express.js request payload
* @param {response} response The response to send back
*/
module.exports = async (client, request, response) => {
const interaction = request.body;
const args = interaction.data.options;

if (!interaction.guild_id) {
response.send({
type: 4,
data: {
content: 'Unfortunately, this command cannot be used on direct messages. Try running `/invite` to invite me to your server.'
}
});
}

if ((interaction.member.permissions & 8208) == 0) {
response.send({
type: 4,
data: {
content: 'You do not have both the `MANAGE_CHANNELS` and the `MANAGE_MESSAGES` permissions.'
}
});
}

if (interaction.data.resolved.channels[interaction.data.options[0].value].type !== 0) {
response.send({
type: 4,
data: {
content: 'You need to input a valid server text channel.'
}
});
}

await Guild.findOneAndUpdate(
{
guildID: interaction.guild_id,
},
{
$addToSet: {
disableStickerUsage: {
$each: args.find(option => option.name === 'channel').value,
},
},
},
{
upsert: true,
},
);

response.send({
type: 4,
data: {
embeds: [{
description: 'Stickers will be deleted in the given channel(s).',
color: [254, 251, 251]
}]
}
});
};
73 changes: 73 additions & 0 deletions src/Interactions/stickers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const fetch = require('node-fetch');
const Guild = require('../Models/Guild.js');

/**
* Allows stickers in the specified channel(s)
* @param {client} client Discord.js client instance
* @param {Object} request Express.js request payload
* @param {response} response The response to send back
*/
module.exports = async (client, request, response) => {
const interaction = request.body;
const args = interaction.data.options;

if (!interaction.guild_id) {
response.send({
type: 4,
data: {
content: 'Unfortunately, this command cannot be used on direct messages. Try running `/invite` to invite me to your server.'
}
});
}

if ((interaction.member.permissions & 8208) == 0) {
response.send({
type: 4,
data: {
content: 'You do not have both the `MANAGE_CHANNELS` and the `MANAGE_MESSAGES` permissions.'
}
});
}

if (interaction.data.resolved.channels[interaction.data.options[0].value].type !== 0) {
response.send({
type: 4,
data: {
content: 'You need to input a valid server text channel.'
}
});
}

await Guild.findOneAndUpdate(
{
guildID: interaction.guild_id,
},
{
$pullAll: {
disableStickerUsage: args.find(option => option.name === 'channel').value,
},
},
{
upsert: true,
},
);

response.send({
type: 4,
data: {
embeds: [{
description: 'Stickers will be allowed in the given channel(s).',
color: [254, 251, 251]
}]
}
});

setTimeout(() => {
fetch(`https://discord.com/api/webhooks/${client.user.id}/${interaction.token}/messages/@original`, {
method: 'DELETE',
headers: {
'Authorization': `Bot ${client.token ?? client.config.token}`,
}
});
}, 10000);
};
5 changes: 3 additions & 2 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
module.exports = {
module.exports = {
publicKey: 'YOUR_APP_PUBLIC_KEY',
prefix: 'YOUR_BOT_PREFIX',
token: 'YOUR_BOT_TOKEN',
mongoURL: ',YOUR_MONGODB_URL',
ownerIDs: [
'YOUR_USER_ID'
]
};
};
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ connect(client.config.mongoURL, {
});
});
}).catch((e) => console.log(chalk.red(e)));

require('./server.js')(client);
30 changes: 30 additions & 0 deletions src/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const { verifyKeyMiddleware } = require('discord-interactions');
const server = require('express')();
const fs = require('fs');

const files = fs.readdirSync('./Interactions').filter(file => file.endsWith('.js'));

module.exports = (client) => {
server.post('/interactions', verifyKeyMiddleware(client.config.publicKey), (request, response) => {
const interaction = request.body;

if (interaction.type == 1) {
response.send({ type: 1 });
}

if (interaction.type == 2) {
if (!files.has(interaction.data.name + '.js')) {
response.send({
type: 4,
data: {
content: 'The invoked slash command could not be found.',
flags: 64
}
});
}
require(`./interactions/${interaction.data.name + '.js'}`)(client, request, response);
}
});

server.listen(8000);
};

0 comments on commit 1c3d78a

Please sign in to comment.