diff --git a/commands/about.js b/commands/about.js
new file mode 100644
index 0000000..ccf1856
--- /dev/null
+++ b/commands/about.js
@@ -0,0 +1,76 @@
+const { SlashCommandBuilder } = require('@discordjs/builders');
+const { MessageEmbed } = require('discord.js');
+
+const gitlog = require('gitlog').default;
+
+const userScore = require('../models/userScore');
+
+module.exports = {
+ data: new SlashCommandBuilder()
+ .setName('about')
+ .setDescription('Commands regarding the creation/development of the bot')
+ .addSubcommand(subcommand => {
+ subcommand
+ .setName('contributors')
+ .setDescription('Lists contributors to the AwesomeSciBo bot');
+ return subcommand;
+ })
+ .addSubcommand(subcommand => {
+ subcommand
+ .setName('changelog')
+ .setDescription('Lists the 5 most recent changes in a "git log" type format');
+ return subcommand;
+ })
+ .addSubcommand(subcommand => {
+ subcommand
+ .setName('bot')
+ .setDescription('Lists information about AwesomeSciBo');
+ return subcommand;
+ }),
+ async execute(interaction) {
+ const client = interaction.client;
+ const action = interaction.options.getSubcommand();
+ if (action === 'contributors') {
+ const contributorEmbed = new MessageEmbed().setTitle('Contributors')
+ .addField('Creator', '<@745063586422063214> [ADawesomeguy#3602]', true)
+ .addField('Contributors', '<@650525101048987649> [tEjAs#8127]\n<@426864344463048705> [tetrident#9396]', true) // Add more contributors here, first one is Abheek, second one is Tejas
+ .setTimestamp()
+ .setColor('#ffffff');
+
+ interaction.reply({ embeds: [contributorEmbed] });
+ }
+ else if (action === 'changelog') {
+ const gitRepoLocation = __dirname;
+
+ const commits = gitlog({
+ repo: gitRepoLocation,
+ number: 5,
+ fields: ['hash', 'abbrevHash', 'subject', 'authorName', 'authorDateRel'],
+ });
+
+ const changelogEmbed = new MessageEmbed()
+ .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() })
+ .setTitle('Changelog')
+ .setColor('#ffffff')
+ .setTimestamp();
+
+ commits.forEach(commit => {
+ changelogEmbed.addField(commit.abbrevHash, `> \`Hash:\`${commit.hash}\n> \`Subject:\`${commit.subject}\n> \`Author:\`${commit.authorName}\n> \`Date:\`${commit.authorDateRel}\n> \`Link\`: [GitHub](https://github.com/ADawesomeguy/AwesomeSciBo/commit/${commit.hash})\n`);
+ });
+
+ interaction.reply({ embeds: [changelogEmbed] });
+ }
+ else if (action === 'bot') {
+ await client.guilds.fetch();
+ const trainingDocuments = await userScore.countDocuments({});
+ const aboutBotEmbed = new MessageEmbed()
+ .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() })
+ .setTitle('About AwesomeSciBo')
+ .addField('Servers', `${client.guilds.cache.size}`, true)
+ .addField('Training Users', `${trainingDocuments}`, true)
+ .setTimestamp();
+
+ interaction.reply({ embeds: [aboutBotEmbed] });
+ }
+ },
+};
diff --git a/commands/help.js b/commands/help.js
new file mode 100644
index 0000000..154795e
--- /dev/null
+++ b/commands/help.js
@@ -0,0 +1,14 @@
+const { SlashCommandBuilder } = require('@discordjs/builders');
+const { MessageEmbed } = require('discord.js');
+
+module.exports = {
+ data: new SlashCommandBuilder()
+ .setName('help')
+ .setDescription('Replies with a help message explaining what the bot can do'),
+ async execute(interaction) {
+ const helpEmbed = new MessageEmbed()
+ .setDescription('AwesomeSciBo has migrated to using slash commands! You can take a look at the different commands by typing `/` and clicking on the AwesomeSciBo icon.')
+ .setColor('#ffffff');
+ interaction.reply({ embeds: [helpEmbed] });
+ },
+};
diff --git a/commands/rounds.js b/commands/rounds.js
new file mode 100644
index 0000000..a9167c0
--- /dev/null
+++ b/commands/rounds.js
@@ -0,0 +1,110 @@
+const { SlashCommandBuilder } = require('@discordjs/builders');
+const { MessageEmbed } = require('discord.js');
+
+const axios = require('axios');
+
+const generatedRound = require('../models/generateRound');
+
+module.exports = {
+ data: new SlashCommandBuilder()
+ .setName('rounds')
+ .setDescription('Commands regarding the generation of rounds')
+ .addSubcommand(subcommand => {
+ subcommand
+ .setName('generate')
+ .setDescription('Generates a round with randomized questions from https://scibowldb.com/');
+ return subcommand;
+ })
+ .addSubcommand(subcommand => {
+ subcommand
+ .setName('list')
+ .setDescription('Lists your 5 most recently generated rounds with links');
+ return subcommand;
+ })
+ .addSubcommand(subcommand => {
+ subcommand
+ .setName('hit')
+ .setDescription('Shows the total number of rounds hit as well as the number for the specific user');
+ return subcommand;
+ }),
+ async execute(interaction) {
+ const action = interaction.options.getSubcommand();
+ if (action === 'generate') {
+ let i;
+ let finalizedHTML = '
ROUND GENERATED BY AWESOMESCIBO USING THE SCIBOWLDB API
';
+ let tossup_question;
+ let question_category;
+ let tossup_format;
+ let tossup_answer;
+ let bonus_question;
+ let bonus_format;
+ let bonus_answer;
+ let htmlContent = '';
+ await axios.post('https://scibowldb.com/api/questions', { categories: ['BIOLOGY', 'PHYSICS', 'CHEMISTRY', 'EARTH AND SPACE', 'ASTRONOMY', 'MATH'] })
+ .then((response) => {
+ for (i = 1; i < 26; i++) {
+ const data = response.data.questions[Math.floor(Math.random() * response.data.questions.length)];
+ tossup_question = data.tossup_question;
+ tossup_answer = data.tossup_answer;
+ question_category = data.category;
+ tossup_format = data.tossup_format;
+ bonus_question = data.bonus_question;
+ bonus_answer = data.bonus_answer;
+ bonus_format = data.bonus_format;
+ htmlContent = '
TOSS-UP
\n
' + `${i}) ${question_category}` + ' ' + `${tossup_format}` + ' ' + tossup_question + '
' + 'ANSWER: ' + tossup_answer + '
';
+ htmlContent += '
BONUS
\n
' + `${i}) ${question_category}` + ' ' + `${bonus_format}` + ' ' + bonus_question + '
' + 'ANSWER: ' + bonus_answer + '
';
+ htmlContent = htmlContent.replace(/\n/g, '
');
+ finalizedHTML += htmlContent;
+ }
+
+ const newGeneratedRound = new generatedRound({
+ htmlContent: finalizedHTML,
+ requestedBy: interaction.user.id,
+ authorTag: interaction.user.tag,
+ timestamp: new Date().toISOString(),
+ });
+
+ newGeneratedRound.save((err, round) => {
+ if (err) {
+ console.log(err);
+ return;
+ }
+ interaction.reply(`Here's your round: https://api.adawesome.tech/round/${round._id.toString()}`, { ephemeral: true });
+ });
+ });
+ }
+ else if (action === 'list') {
+ let roundsList = await generatedRound.find({ requestedBy: interaction.user.id }).sort({ timestamp: -1 });
+ let finalMessage = '';
+ if (!roundsList) {
+ interaction.reply('You haven\'t requested any roundsList!');
+ return;
+ }
+
+ if (roundsList.length > 5) {
+ roundsList = roundsList.slice(0, 5);
+ }
+
+ roundsList.forEach(async (item, index) => {
+ finalMessage += `${index + 1}. [${item.timestamp.split('T')[0]}](https://api.adawesome.tech/round/${item._id.toString()})\n`;
+ });
+
+ const roundsListEmbed = new MessageEmbed()
+ .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() })
+ .setTitle(`Last 5 roundsList requested by ${interaction.user.tag}`)
+ .setDescription(finalMessage)
+ .setTimestamp();
+
+ interaction.reply({
+ embeds: [roundsListEmbed],
+ ephemeral: true,
+ });
+ }
+ else if (action === 'hit') {
+ const totalCount = await generatedRound.countDocuments({});
+ const userCount = await generatedRound.countDocuments({ requestedBy: interaction.user.id });
+
+ interaction.reply(`Total Hits: ${totalCount}\nYour Hits: ${userCount}`);
+ }
+ },
+};
diff --git a/commands/top.js b/commands/top.js
new file mode 100644
index 0000000..bb5abb9
--- /dev/null
+++ b/commands/top.js
@@ -0,0 +1,39 @@
+const { SlashCommandBuilder } = require('@discordjs/builders');
+const { MessageEmbed } = require('discord.js');
+
+const userScore = require('../models/userScore');
+
+module.exports = {
+ data: new SlashCommandBuilder()
+ .setName('top')
+ .setDescription('Lists top ten scores across servers (server specific leaderboard WIP)'),
+ async execute(interaction) {
+ let messageContent = '';
+ userScore
+ .find({})
+ .sort({ score: -1 }) // Sort by descending order
+ .exec((err, obj) => {
+ if (err) {
+ console.log(err);
+ return interaction.reply(
+ 'Uh oh! :( There was an internal error. Please try again.',
+ );
+ }
+ if (obj.length < 10) {
+ // Need at least 10 scores for top 10
+ return interaction.reply(
+ `There are only ${obj.length} users, we need at least 10!`,
+ );
+ }
+ for (let i = 0; i < 10; i++) {
+ messageContent += `${i + 1}: <@${obj[i].authorID}>: ${obj[i].score}\n`; // Loop through each user and add their name and score to leaderboard content
+ }
+ const leaderboardEmbed = new MessageEmbed()
+ .setTitle('Top Ten!')
+ .setDescription(messageContent)
+ .setColor('#ffffff');
+
+ interaction.reply({ embeds: [leaderboardEmbed] });
+ });
+ },
+};
diff --git a/commands/train.js b/commands/train.js
new file mode 100644
index 0000000..d050dbd
--- /dev/null
+++ b/commands/train.js
@@ -0,0 +1,169 @@
+const { SlashCommandBuilder } = require('@discordjs/builders');
+const { MessageEmbed } = require('discord.js');
+
+const decode = require('html-entities').decode;
+const axios = require('axios');
+
+const userScore = require('../models/userScore');
+
+const { updateScore } = require('../helpers/db.js');
+
+module.exports = {
+ data: new SlashCommandBuilder()
+ .setName('train')
+ .setDescription('Sends a training question to be answered')
+ .addStringOption(option => {
+ option
+ .setName('subject')
+ .setDescription('Optional subject to be used as a filter')
+ .setRequired(false)
+ .addChoice('astro', 'astro')
+ .addChoice('bio', 'bio')
+ .addChoice('ess', 'ess')
+ .addChoice('chem', 'chem')
+ .addChoice('phys', 'phys')
+ .addChoice('math', 'math')
+ .addChoice('energy', 'energy')
+ .setRequired(false);
+ return option;
+ }),
+ async execute(interaction) {
+ const subject = interaction.options.get('subject') ? interaction.options.get('subject').value : null;
+ const authorId = interaction.user.id;
+ let score;
+ userScore
+ .findOne({ authorID: authorId })
+ .lean()
+ .then((obj, err) => {
+ if (!obj) {
+ score = 0;
+ }
+ else if (obj) {
+ score = obj.score;
+ }
+ else {
+ console.log(err);
+ }
+ });
+
+ let categoryArray = [];
+
+ switch (subject) {
+ case null:
+ categoryArray = ['BIOLOGY', 'PHYSICS', 'CHEMISTRY', 'EARTH AND SPACE', 'ASTRONOMY', 'MATH'];
+ break;
+ case 'astro':
+ case 'astronomy':
+ categoryArray = ['ASTRONOMY'];
+ break;
+ case 'bio':
+ case 'biology':
+ categoryArray = ['BIOLOGY'];
+ break;
+ case 'ess':
+ case 'earth science':
+ case 'es':
+ categoryArray = ['EARTH SCIENCE'];
+ break;
+ case 'chem':
+ case 'chemistry':
+ categoryArray = ['CHEMISTRY'];
+ break;
+ case 'phys':
+ case 'physics':
+ categoryArray = ['PHYSICS'];
+ break;
+ case 'math':
+ categoryArray = ['MATH'];
+ break;
+ case 'energy':
+ categoryArray = ['ENERGY'];
+ break;
+ default:
+ interaction.reply(
+ new MessageEmbed()
+ .setDescription('<:red_x:816791117671825409> Not a valid subject!')
+ .setColor('#ffffff'),
+ );
+ return;
+ }
+
+ axios
+ .post('https://scibowldb.com/api/questions/random', { categories: categoryArray })
+ .then((res) => {
+ const data = res.data.question;
+ const tossupQuestion = data.tossup_question;
+ const tossupAnswer = data.tossup_answer;
+ const messageFilter = message => message.author.id === interaction.author.id;
+ interaction.reply({ content: decode(tossupQuestion) + `\n\n||Source: ${data.uri}||` })
+ .then(() => {
+ interaction.channel.awaitMessages({
+ messageFilter,
+ max: 1,
+ })
+ .then(collected => {
+ console.log(collected.first());
+ const answerMsg = collected.first();
+
+ let predicted = null;
+ if (data.tossup_format === 'Multiple Choice') {
+ if (
+ answerMsg.content.charAt(0).toLowerCase() ===
+ tossupAnswer.charAt(0).toLowerCase()
+ ) {
+ predicted = 'correct';
+ }
+ else {
+ predicted = 'incorrect';
+ }
+ }
+ else if (
+ answerMsg.content.toLowerCase() ===
+ tossupAnswer.toLowerCase()
+ ) {
+ predicted = 'correct';
+ }
+ else {
+ predicted = 'incorrect';
+ }
+
+ if (predicted === 'correct') {
+ updateScore(true, score, authorId).then((msgToReply) =>
+ answerMsg.reply(msgToReply),
+ );
+ }
+ else {
+ const overrideEmbed = new MessageEmbed()
+ .setAuthor({ name: answerMsg.author.tag, iconURL: answerMsg.author.displayAvatarURL() })
+ .addField('Correct answer', `\`${tossupAnswer}\``)
+ .setDescription('It seems your answer was incorrect. Please react with <:override:842778128966615060> to override your answer if you think you got it right.')
+ .setColor('#ffffff')
+ .setTimestamp();
+ answerMsg.channel.send({
+ embeds: [overrideEmbed],
+ })
+ .then(overrideMsg => {
+ overrideMsg.react('<:override:842778128966615060>');
+ const filter = (reaction, user) => {
+ return (
+ ['override'].includes(reaction.emoji.name) &&
+ user.id === answerMsg.author.id
+ );
+ };
+ overrideMsg
+ .awaitReactions({
+ filter,
+ max: 1,
+ })
+ .then(() => {
+ updateScore(true, score, authorId).then((msgToReply) =>
+ answerMsg.reply(msgToReply),
+ );
+ }).catch(console.error);
+ }).catch(console.error);
+ }
+ }).catch(console.error);
+ }).catch(console.error);
+ }).catch(console.error);
+ },
+};
diff --git a/deploy-commands.js b/deploy-commands.js
new file mode 100755
index 0000000..0b7b816
--- /dev/null
+++ b/deploy-commands.js
@@ -0,0 +1,20 @@
+#!/usr/bin/env node
+
+const fs = require('node:fs');
+const { REST } = require('@discordjs/rest');
+const { Routes } = require('discord-api-types/v9');
+const { clientId, token } = require('./helpers/env');
+
+const commands = [];
+const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
+
+for (const file of commandFiles) {
+ const command = require(`./commands/${file}`);
+ commands.push(command.data.toJSON());
+}
+
+const rest = new REST({ version: '9' }).setToken(token);
+
+rest.put(Routes.applicationCommands(clientId), { body: commands })
+ .then(() => console.log('Successfully registered application commands.'))
+ .catch(console.error);
diff --git a/events/interactionCreate.js b/events/interactionCreate.js
new file mode 100644
index 0000000..e364cf2
--- /dev/null
+++ b/events/interactionCreate.js
@@ -0,0 +1,20 @@
+module.exports = {
+ name: 'interactionCreate',
+ once: false,
+ async execute(interaction) {
+ const client = interaction.client;
+ if (!interaction.isCommand()) return;
+
+ const command = client.commands.get(interaction.commandName);
+
+ if (!command) return;
+
+ try {
+ await command.execute(interaction);
+ }
+ catch (error) {
+ console.error(error);
+ await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
+ }
+ },
+};
diff --git a/events/ready.js b/events/ready.js
new file mode 100644
index 0000000..e4a0aa7
--- /dev/null
+++ b/events/ready.js
@@ -0,0 +1,11 @@
+const db = require('../helpers/db');
+const { mongoUri } = require('../helpers/env');
+
+module.exports = {
+ name: 'ready',
+ once: true,
+ async execute(client) {
+ await db.connect(mongoUri);
+ console.log(`Logged in at ${client.user.tag}!`);
+ },
+};
diff --git a/helpers/db.js b/helpers/db.js
new file mode 100644
index 0000000..4754b42
--- /dev/null
+++ b/helpers/db.js
@@ -0,0 +1,41 @@
+const mongoose = require('mongoose');
+
+const userScore = require('../models/userScore');
+
+module.exports = {
+ async updateScore(isCorrect, score, authorId) {
+ if (!isCorrect) {
+ return `Nice try! Your score is still ${score}.`;
+ }
+ else {
+ score += 4;
+ if (score == 4) {
+ const newUserScore = new userScore({
+ authorID: authorId,
+ score: score,
+ });
+ newUserScore.save((err) =>
+ err
+ ? console.log('Error creating new user for scoring')
+ : console.log('Sucessfully created user to score.'),
+ );
+ }
+ else {
+ const doc = await userScore.findOne({
+ authorID: authorId,
+ });
+ doc.score = doc.score + 4;
+ doc.save();
+ }
+
+ return `Great job! Your score is now ${score}.`;
+ }
+ },
+ async connect(mongoUri) {
+ mongoose
+ .connect(mongoUri, {
+ useUnifiedTopology: true,
+ useNewUrlParser: true,
+ });
+ },
+};
diff --git a/helpers/env.js b/helpers/env.js
new file mode 100644
index 0000000..69f0af6
--- /dev/null
+++ b/helpers/env.js
@@ -0,0 +1,8 @@
+require('dotenv').config();
+
+module.exports = {
+ clientId: process.env.CLIENT_ID,
+ testingGuild: process.env.TESTING_GUILD,
+ token: process.env.TOKEN,
+ mongoUri: process.env.MONGO_URI,
+};
diff --git a/index.js b/index.js
index 6bd39b0..3104c0f 100755
--- a/index.js
+++ b/index.js
@@ -1,437 +1,31 @@
#!/usr/bin/env node
-require('dotenv').config();
+const fs = require('node:fs');
+const { Client, Collection, Intents } = require('discord.js');
+const { token } = require('./helpers/env');
-const Discord = require('discord.js');
-const client = new Discord.Client({
- intents: ['GUILDS', 'GUILD_MESSAGES', 'GUILD_MESSAGE_REACTIONS', 'DIRECT_MESSAGES', 'DIRECT_MESSAGE_REACTIONS'],
- partials: ['MESSAGE', 'CHANNEL', 'REACTION'],
+const client = new Client({
+ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_MESSAGE_REACTIONS, Intents.FLAGS.DIRECT_MESSAGES, Intents.FLAGS.DIRECT_MESSAGE_REACTIONS],
});
-const axios = require('axios');
-const mongoose = require('mongoose');
-const gitlog = require('gitlog').default;
-const decode = require('html-entities').decode;
-const userScore = require('./models/userScore');
-const generatedRound = require('./models/generateRound');
+client.commands = new Collection();
-const helpMessage = 'AwesomeSciBo has migrated to using slash commands! You can take a look at the different commands by typing `/` and clicking on the AwesomeSciBo icon.';
-const slashCommands = require('./slashCommands.json');
-const config = {
- topggauth: process.env['TOPGGAUTH'],
-};
+const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
+const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js'));
-client.once('ready', () => {
- client.application.commands.set(slashCommands);
-
- // Connect to MongoDB using mongoose
- if (!process.env.CI) {
- mongoose
- .connect(process.env.MONGO_URI, {
- useUnifiedTopology: true,
- useNewUrlParser: true,
- })
- .then(() => {
- // Log client tag and set status
- console.log(`Logged in as: ${client.user.username}!`);
- client.user.setActivity(
- 'for /help',
- { type: 'WATCHING' },
- );
- })
- .catch((err) => console.log(err));
- }
-});
-
-client.on('guildCreate', () => {
- const topggAuthHeader = {
- headers: {
- 'Authorization': config.topggauth,
- },
- };
- axios.post(`https://top.gg/api/bots/${client.user.id}/stats`, { server_count: client.guilds.cache.size }, topggAuthHeader).then(response => { console.log(response); });
-});
-
-client.on('guildDelete', () => {
- const topggAuthHeader = {
- headers: {
- 'Authorization': config.topggauth,
- },
- };
- axios.post(`https://top.gg/api/bots/${client.user.id}/stats`, { server_count: client.guilds.cache.size }, topggAuthHeader);
-});
-
-async function updateScore(isCorrect, score, authorId) {
- if (!isCorrect) {
- return `Nice try! Your score is still ${score}.`;
- }
- else {
- score += 4;
- if (score == 4) {
- const newUserScore = new userScore({
- authorID: authorId,
- score: score,
- });
- newUserScore.save((err) =>
- err
- ? console.log('Error creating new user for scoring')
- : console.log('Sucessfully created user to score.'),
- );
- }
- else {
- const doc = await userScore.findOne({
- authorID: authorId,
- });
- doc.score = doc.score + 4;
- doc.save();
- }
-
- return `Great job! Your score is now ${score}.`;
- }
+for (const file of commandFiles) {
+ const command = require(`./commands/${file}`);
+ client.commands.set(command.data.name, command);
}
-async function training(subject, interaction) {
- const authorId = interaction.user.id;
- let score;
- userScore
- .findOne({ authorID: authorId })
- .lean()
- .then((obj, err) => {
- if (!obj) {
- score = 0;
- }
- else if (obj) {
- score = obj.score;
- }
- else {
- console.log(err);
- }
- });
-
- let categoryArray = [];
-
- switch (subject) {
- case null:
- categoryArray = ['BIOLOGY', 'PHYSICS', 'CHEMISTRY', 'EARTH AND SPACE', 'ASTRONOMY', 'MATH'];
- break;
- case 'astro':
- case 'astronomy':
- categoryArray = ['ASTRONOMY'];
- break;
- case 'bio':
- case 'biology':
- categoryArray = ['BIOLOGY'];
- break;
- case 'ess':
- case 'earth science':
- case 'es':
- categoryArray = ['EARTH SCIENCE'];
- break;
- case 'chem':
- case 'chemistry':
- categoryArray = ['CHEMISTRY'];
- break;
- case 'phys':
- case 'physics':
- categoryArray = ['PHYSICS'];
- break;
- case 'math':
- categoryArray = ['MATH'];
- break;
- case 'energy':
- categoryArray = ['ENERGY'];
- break;
- default:
- interaction.reply(
- new Discord.MessageEmbed()
- .setDescription('<:red_x:816791117671825409> Not a valid subject!')
- .setColor('#ffffff'),
- );
- return;
+for (const file of eventFiles) {
+ const event = require(`./events/${file}`);
+ if (event.once) {
+ client.once(event.name, (...args) => event.execute(...args));
}
-
- axios
- .post('https://scibowldb.com/api/questions/random', { categories: categoryArray })
- .then((res) => {
- const data = res.data.question;
- const tossupQuestion = data.tossup_question;
- const tossupAnswer = data.tossup_answer;
- const messageFilter = message => message.author.id === interaction.author.id;
- interaction.reply({ content: decode(tossupQuestion) + `\n\n||Source: ${data.uri}||` })
- .then(() => {
- interaction.channel.awaitMessages({
- messageFilter,
- max: 1,
- })
- .then(collected => {
- console.log(collected.first());
- const answerMsg = collected.first();
-
- let predicted = null;
- if (data.tossup_format === 'Multiple Choice') {
- if (
- answerMsg.content.charAt(0).toLowerCase() ===
- tossupAnswer.charAt(0).toLowerCase()
- ) {
- predicted = 'correct';
- }
- else {
- predicted = 'incorrect';
- }
- }
- else if (
- answerMsg.content.toLowerCase() ===
- tossupAnswer.toLowerCase()
- ) {
- predicted = 'correct';
- }
- else {
- predicted = 'incorrect';
- }
-
- if (predicted === 'correct') {
- updateScore(true, score, authorId).then((msgToReply) =>
- answerMsg.reply(msgToReply),
- );
- }
- else {
- const overrideEmbed = new Discord.MessageEmbed()
- .setAuthor({ name: answerMsg.author.tag, iconURL: answerMsg.author.displayAvatarURL() })
- .addField('Correct answer', `\`${tossupAnswer}\``)
- .setDescription('It seems your answer was incorrect. Please react with <:override:842778128966615060> to override your answer if you think you got it right.')
- .setColor('#ffffff')
- .setTimestamp();
- answerMsg.channel.send({
- embeds: [overrideEmbed],
- })
- .then(overrideMsg => {
- overrideMsg.react('<:override:842778128966615060>');
- const filter = (reaction, user) => {
- return (
- ['override'].includes(reaction.emoji.name) &&
- user.id === answerMsg.author.id
- );
- };
- overrideMsg
- .awaitReactions({
- filter,
- max: 1,
- })
- .then(() => {
- updateScore(true, score, authorId).then((msgToReply) =>
- answerMsg.reply(msgToReply),
- );
- }).catch(console.error);
- }).catch(console.error);
- }
- }).catch(console.error);
- }).catch(console.error);
- }).catch(console.error);
-}
-
-function sendHelpMessage(interaction) {
- const helpEmbed = new Discord.MessageEmbed().setDescription(helpMessage).setColor('ffffff');
- interaction.reply({ embeds: [helpEmbed] });
-}
-
-function showLeaderboard(interaction) {
- let messageContent = '';
- userScore
- .find({})
- .sort({ score: -1 }) // Sort by descending order
- .exec((err, obj) => {
- if (err) {
- console.log(err);
- return interaction.reply(
- 'Uh oh! :( There was an internal error. Please try again.',
- );
- }
- if (obj.length < 10) {
- // Need at least 10 scores for top 10
- return interaction.reply(
- `There are only ${obj.length} users, we need at least 10!`,
- );
- }
- for (let i = 0; i < 10; i++) {
- messageContent += `${i + 1}: <@${obj[i].authorID}>: ${obj[i].score}\n`; // Loop through each user and add their name and score to leaderboard content
- }
- const leaderboardEmbed = new Discord.MessageEmbed()
- .setTitle('Top Ten!')
- .setDescription(messageContent)
- .setColor('#ffffff');
-
- interaction.reply({ embeds: [leaderboardEmbed] });
- });
-}
-
-async function about(action, interaction) {
- if (action === 'contributors') {
- const contributorEmbed = new Discord.MessageEmbed().setTitle('Contributors')
- .addField('Creator', '<@745063586422063214> [ADawesomeguy#3602]', true)
- .addField('Contributors', '<@650525101048987649> [tEjAs#8127]\n<@426864344463048705> [tetrident#9396]', true) // Add more contributors here, first one is Abheek, second one is Tejas
- .setTimestamp()
- .setColor('#ffffff');
-
- interaction.reply({ embeds: [contributorEmbed] });
- }
- else if (action === 'changelog') {
- const gitRepoLocation = __dirname;
-
- const commits = gitlog({
- repo: gitRepoLocation,
- number: 5,
- fields: ['hash', 'abbrevHash', 'subject', 'authorName', 'authorDateRel'],
- });
-
- const changelogEmbed = new Discord.MessageEmbed()
- .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() })
- .setTitle('Changelog')
- .setColor('#ffffff')
- .setTimestamp();
-
- commits.forEach(commit => {
- changelogEmbed.addField(commit.abbrevHash, `> \`Hash:\`${commit.hash}\n> \`Subject:\`${commit.subject}\n> \`Author:\`${commit.authorName}\n> \`Date:\`${commit.authorDateRel}\n> \`Link\`: [GitHub](https://github.com/ADawesomeguy/AwesomeSciBo/commit/${commit.hash})\n`);
- });
-
- interaction.reply({ embeds: [changelogEmbed] });
- }
- else if (action === 'bot') {
- await client.guilds.fetch();
- const trainingDocuments = await userScore.countDocuments({});
- const aboutBotEmbed = new Discord.MessageEmbed()
- .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() })
- .setTitle('About AwesomeSciBo')
- .addField('Servers', `${client.guilds.cache.size}`, true)
- .addField('Training Users', `${trainingDocuments}`, true)
- .setTimestamp();
-
- interaction.reply({ embeds: [aboutBotEmbed] });
- }
-}
-
-async function rounds(action, interaction) {
- if (action === 'generate') {
- let i;
- let finalizedHTML = ' ROUND GENERATED BY AWESOMESCIBO USING THE SCIBOWLDB API
';
- let tossup_question;
- let question_category;
- let tossup_format;
- let tossup_answer;
- let bonus_question;
- let bonus_format;
- let bonus_answer;
- let htmlContent = '';
- await axios.post('https://scibowldb.com/api/questions', { categories: ['BIOLOGY', 'PHYSICS', 'CHEMISTRY', 'EARTH AND SPACE', 'ASTRONOMY', 'MATH'] })
- .then((response) => {
- for (i = 1; i < 26; i++) {
- const data = response.data.questions[Math.floor(Math.random() * response.data.questions.length)];
- tossup_question = data.tossup_question;
- tossup_answer = data.tossup_answer;
- question_category = data.category;
- tossup_format = data.tossup_format;
- bonus_question = data.bonus_question;
- bonus_answer = data.bonus_answer;
- bonus_format = data.bonus_format;
- htmlContent = '
TOSS-UP
\n
' + `${i}) ${question_category}` + ' ' + `${tossup_format}` + ' ' + tossup_question + '
' + 'ANSWER: ' + tossup_answer + '
';
- htmlContent += '
BONUS
\n
' + `${i}) ${question_category}` + ' ' + `${bonus_format}` + ' ' + bonus_question + '
' + 'ANSWER: ' + bonus_answer + '
';
- htmlContent = htmlContent.replace(/\n/g, '
');
- finalizedHTML += htmlContent;
- }
-
- const newGeneratedRound = new generatedRound({
- htmlContent: finalizedHTML,
- requestedBy: interaction.user.id,
- authorTag: interaction.user.tag,
- timestamp: new Date().toISOString(),
- });
-
- newGeneratedRound.save((err, round) => {
- if (err) {
- console.log(err);
- return;
- }
- interaction.reply(`Here's your round: https://api.adawesome.tech/round/${round._id.toString()}`, { ephemeral: true });
- });
- });
- }
- else if (action === 'list') {
- let roundsList = await generatedRound.find({ requestedBy: interaction.user.id }).sort({ timestamp: -1 });
- let finalMessage = '';
- if (!roundsList) {
- interaction.reply('You haven\'t requested any roundsList!');
- return;
- }
-
- if (roundsList.length > 5) {
- roundsList = roundsList.slice(0, 5);
- }
-
- roundsList.forEach(async (item, index) => {
- finalMessage += `${index + 1}. [${item.timestamp.split('T')[0]}](https://api.adawesome.tech/round/${item._id.toString()})\n`;
- });
-
- const roundsListEmbed = new Discord.MessageEmbed()
- .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() })
- .setTitle(`Last 5 roundsList requested by ${interaction.user.tag}`)
- .setDescription(finalMessage)
- .setTimestamp();
-
- interaction.reply({
- embeds: [roundsListEmbed],
- ephemeral: true,
- });
- }
- else if (action === 'hit') {
- const totalCount = await generatedRound.countDocuments({});
- const userCount = await generatedRound.countDocuments({ requestedBy: interaction.user.id });
-
- interaction.reply(`Total Hits: ${totalCount}\nYour Hits: ${userCount}`);
- }
-}
-
-async function result(interaction) {
- if (interaction.channel.id !== '930275699644825600') {
- return interaction.reply({ content: 'This command is unavailable outside of the designated channel.', ephemeral: true });
+ else {
+ client.on(event.name, (...args) => event.execute(...args));
}
- const resultEmbed = new Discord.MessageEmbed();
- resultEmbed.setTitle(`${interaction.options.get('location').value} Regionals`);
- resultEmbed.setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() });
- resultEmbed.addField(' Winner', `Congratulations to **${interaction.options.get('winner').value}**!`);
- if (interaction.options.get('runner-up')) resultEmbed.addField('<:second:932138645601800252> Runners-Up', interaction.options.get('runner-up').value);
- if (interaction.options.get('third-place')) resultEmbed.addField('<:third:932138645526315080> Third Place', interaction.options.get('third-place').value);
- if (interaction.options.get('honorable-mentions')) resultEmbed.addField('🎖️ Honorable Mentions', interaction.options.get('honorable-mentions').value);
- resultEmbed.setColor('#FFFFFF');
- resultEmbed.setTimestamp();
-
- await interaction.reply({ embeds: [resultEmbed] });
}
-client.on('interactionCreate', async interaction => {
- // If the interaction isn't a slash command, return
- if (!interaction.isCommand()) return;
-
- switch (interaction.commandName) {
- case 'help':
- sendHelpMessage(interaction);
- break;
- case 'train':
- training(interaction.options.get('subject') ? interaction.options.get('subject').value : null, interaction);
- break;
- case 'roundsList':
- rounds(interaction.options.getSubcommand(), interaction);
- break;
- case 'top':
- showLeaderboard(interaction);
- break;
- case 'about':
- about(interaction.options.getSubcommand(), interaction);
- break;
- case 'result':
- result(interaction);
- }
-});
-
-client
- .login(process.env.TOKEN)
- .then(() => console.log('Running!'))
- .catch((error) => console.log(error));
+client.login(token);
diff --git a/package.json b/package.json
index 466668a..eb6edc3 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,6 @@
{
"dependencies": {
+ "@discordjs/rest": "^0.3.0",
"axios": "^0.21.1",
"discord.js": "^13.2.0",
"dotenv": "^8.2.0",
diff --git a/slashCommands.json b/slashCommands.json
deleted file mode 100644
index 9e4a2d6..0000000
--- a/slashCommands.json
+++ /dev/null
@@ -1,137 +0,0 @@
-[
- {
- "name": "train",
- "description": "Sends a single training question to be answered",
- "options": [
- {
- "type": 3,
- "name": "subject",
- "description": "Optional subject to be used as a filter",
- "default": false,
- "required": false,
- "choices": [
- {
- "name": "astro",
- "value": "astro"
- },
- {
- "name": "bio",
- "value": "bio"
- },
- {
- "name": "ess",
- "value": "ess"
- },
- {
- "name": "chem",
- "value": "chem"
- },
- {
- "name": "phys",
- "value": "phys"
- },
- {
- "name": "math",
- "value": "math"
- },
- {
- "name": "energy",
- "value": "energy"
- }
- ]
- }
- ]
- },
- {
- "name": "help",
- "description": "Replies with a help message explaining what the bot can do"
- },
- {
- "name": "rounds",
- "options": [
- {
- "type": 1,
- "name": "generate",
- "description": "Generates a round with randomized questions from https://scibowldb.com/",
- "options": []
- },
- {
- "type": 1,
- "name": "list",
- "description": "Lists your 5 most recently generated rounds with links",
- "options": []
- },
- {
- "type": 1,
- "name": "hit",
- "description": "Shows the total number of rounds hit as well as the number for the specific user",
- "options": []
- }
- ],
- "description": "Commands regarding rounds generated by AwesomeSciBo"
- },
- {
- "name": "top",
- "description": "Lists top ten scores across servers (server specific leaderboard WIP)"
- },
- {
- "name": "about",
- "options": [
- {
- "type": 1,
- "name": "contributors",
- "description": "Lists contributors to the AwesomeSciBo bot",
- "options": []
- },
- {
- "type": 1,
- "name": "changelog",
- "description": "Lists the 5 most recent changes in a \"git log\" type format",
- "options": []
- },
- {
- "type": 1,
- "name": "bot",
- "description": "Lists information about AwesomeSciBo",
- "options": []
- }
- ],
- "description": "Commands regarding the creation/development of the bot"
- },
- {
- "name": "result",
- "description": "The result of a regional",
- "options": [
- {
- "type": "STRING",
- "name": "location",
- "description": "The location of the regional",
- "required": true
- },
- {
- "type": "STRING",
- "name": "winner",
- "description": "The advancing team from the regional",
- "required": true
- },
- {
- "type": "STRING",
- "name": "runner-up",
- "description": "The second-place team from the regional",
- "required": false
- },
- {
- "type": "STRING",
- "name": "third-place",
- "description": "The third-place team from the regional",
- "required": false
- },
- {
- "type": "STRING",
- "name": "honorable-mentions",
- "description": "Any extra teams to be mentioned or a space for technicalities to be explained",
- "required": false
- }
- ]
- }
-]
diff --git a/yarn.lock b/yarn.lock
index a0fe562..43ed07a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -18,6 +18,19 @@
resolved "https://registry.yarnpkg.com/@discordjs/collection/-/collection-0.4.0.tgz#b6488286a1cc7b41b644d7e6086f25a1c1e6f837"
integrity sha512-zmjq+l/rV35kE6zRrwe8BHqV78JvIh2ybJeZavBi5NySjWXqN3hmmAKg7kYMMXSeiWtSsMoZ/+MQi0DiQWy2lw==
+"@discordjs/rest@^0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@discordjs/rest/-/rest-0.3.0.tgz#89e06a42b168c91598891d6bf860353e28fba5d2"
+ integrity sha512-F9aeP3odlAlllM1ciBZLdd+adiAyBj4VaZBejj4UMj4afE2wfCkNTGvYYiRxrXUE9fN7e/BuDP2ePl0tVA2m7Q==
+ dependencies:
+ "@discordjs/collection" "^0.4.0"
+ "@sapphire/async-queue" "^1.1.9"
+ "@sapphire/snowflake" "^3.0.1"
+ discord-api-types "^0.26.1"
+ form-data "^4.0.0"
+ node-fetch "^2.6.5"
+ tslib "^2.3.1"
+
"@eslint/eslintrc@^1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318"
@@ -52,6 +65,11 @@
resolved "https://registry.yarnpkg.com/@sapphire/async-queue/-/async-queue-1.1.9.tgz#ce69611c8753c4affd905a7ef43061c7eb95c01b"
integrity sha512-CbXaGwwlEMq+l1TRu01FJCvySJ1CEFKFclHT48nIfNeZXaAAmmwwy7scUKmYHPUa3GhoMp6Qr1B3eAJux6XgOQ==
+"@sapphire/snowflake@^3.0.1":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@sapphire/snowflake/-/snowflake-3.2.0.tgz#fa915798d0a0ce5fa93b16c793185ae5d0a3f117"
+ integrity sha512-tfHzY+6/5bbHdB+uNqsEQ5rhjaZAoFUrqP/l1S5jwxMdKeSCIiGkJjcE99/WGGdzyWGjTNgNVX/dt4Me/FdMlg==
+
"@sindresorhus/is@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
@@ -428,7 +446,7 @@ denque@^1.4.1:
resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf"
integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==
-discord-api-types@^0.26.0:
+discord-api-types@^0.26.0, discord-api-types@^0.26.1:
version "0.26.1"
resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.26.1.tgz#726f766ddc37d60da95740991d22cb6ef2ed787b"
integrity sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ==
@@ -1108,7 +1126,7 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
-node-fetch@^2.6.1:
+node-fetch@^2.6.1, node-fetch@^2.6.5:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==