#!/usr/bin/env node require('dotenv').config(); 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 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'); const config = require('./config.json'); 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'); 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}.`; } } 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; } 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 = (m) => m.author.id === authorId; interaction.reply({ content: decode(tossupQuestion) + `\n\n||Source: ${data.uri}||` }) .then(() => { interaction.channel.awaitMessages({ messageFilter, max: 1, }) .then(collected => { 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(answerMsg.author.tag, 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(interaction.user.tag, 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(interaction.user.tag, 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 = '