diff --git a/.eslintrc.json b/.eslintrc.json index b46b74b..a47a5e5 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -11,8 +11,9 @@ "node": true, "es6": true }, + "ignorePatterns": ["src/deploy-commands.js"], "rules": { - "arrow-spacing": ["warn", { "before": true, "after": true }], + "arrow-spacing": ["error", { "before": true, "after": true }], "brace-style": ["error", "stroustrup", { "allowSingleLine": true }], "comma-dangle": ["error", "always-multiline"], "comma-spacing": "error", diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e9bb389 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +abheekd@protonmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..9a197fa --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,25 @@ +# Contributing + +## Cloning for Contribution +To set up the development environment to make changes to the code, clone the repo, install dependencies, and run it directly with `node` as Docker doesn't expose as much. + +## Making Changes +To edit the code please keep a few things in mind: +1. Be able to explain changes you make; they should be legible and understandable. +2. Please try to abide by ESLint's rules, setting up ESLint is quite easy to do and not too difficult to follow. + +## Testing Your Code +For testing, make sure to set up the prerequisites: +1. MongoDB: have a MongoDB server set up. +2. Environment Variables: take a look at the `docker-compose.yml` for examples. + +Once that's done, you can run `yarn tsc` or `npx tsc` to build to JavaScript in the `built` directory. Here you'll find `deploy-commands.js` which you need to deploy the slash commands, and `index.js` which you can run to start the bot. + +## Submitting Your Contribution +Creating a PR is easy enough and there are plenty of tutorials to do so. When contributing, please make sure to highlight and explain your change, with any import information additionally included. + +--- + +# Thank you for any contributions! + +--- diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 86e717d..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,66 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "codeql" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '43 14 * * 0' - -jobs: - analyze: - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - language: [ 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # âšī¸ Command-line programs to run using the OS shell. - # đ https://git.io/JvXDl - - # âī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..c4e353b --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,25 @@ +name: "codeql" + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: '43 14 * * 0' + +jobs: + analyze: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: 'javascript' + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/README.md b/README.md index 7415a08..63f3de4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ + +![logo](https://user-images.githubusercontent.com/67982792/160637166-b8c3a390-e4f9-46d1-8738-dcb2d8b9baa7.png) +
A simple Discord bot that automatically generates Science Bowl rounds using the ScibowlDB API!
## Deployment -Deploying this bot to your Discord server is relatively simple: you can add it to your own server by using [this link](http://scibot.adawesome.tech/). +Deploying this bot to your Discord server is relatively simple: you can add it to your own server by using [this link](https://adat.link/awesomescibo). ## Contributing -Please see [the wiki](https://github.com/ADawesomeguy/AwesomeSciBo/wiki/contributing) contributing page. +Please see [CONTRIBUTING.md](https://github.com/ADawesomeguy/AwesomeSciBo/blob/master/.github/CONTRIBUTING.md). ## Installation -Please see [the wiki](https://github.com/ADawesomeguy/AwesomeSciBo/wiki/installation) install page. - -## Usage -This bot uses slash commands now :). You can just click on the bot icon after typing `/` to see a list of commands. +There are basically two ways to install it: -## Notes -### Creating a Discord Application/Bot -To create your own application and bot using the [Discord Developer Portal](https://discord.com/developers), go to the previous link and sign in. Then create a new application, and click bots on the left. Configure it to your liking, and then copy the token. +### Method 1 (Node): +After cloning the repository, dependencies can be installed with `yarn` or `npm i`. The bot can then be compile to JavaScript with `yarn tsc` or `npx tsc`, and will be deployed in the `built/` directory. Finally, the bot can be run by entering said directory and running `./index.js` or `node index.js`. - ![](images/discord-developer.png) +### Method 2 (Docker): +This bot has a Dockerfile within the repository which can be built using `docker build . -t [tag]`. Alternatively and preferably, the image can be taken from [DockerHub](https://hub.docker.com/r/adawesomeguy/awesomescibo). -That's the most important part of your bot *and don't share it with anyone*. +## Usage +This bot uses slash commands now :). You can just click on the bot icon after typing `/` to see a list of commands. ## Credit The bot was made by [@ADawesomeguy](https://github.com/ADawesomeguy). However, the API was made by [@CQCumbers](https://github.com/CQCumbers). Go give [his API](https://github.com/CQCumbers/ScibowlDB) a star, he totally deserves it! diff --git a/images/discord-developer.png b/images/discord-developer.png deleted file mode 100644 index 6d18a4c..0000000 Binary files a/images/discord-developer.png and /dev/null differ diff --git a/package.json b/package.json index 7a6e3bd..dd6560f 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,9 @@ "typescript": "^4.6.2" }, "name": "awesomescibo", - "version": "4.1.1", + "version": "4.3.2", "scripts": { - "start": "node index.js" + "build": "yarn tsc" }, "keywords": [ "discord", @@ -27,7 +27,7 @@ "science bowl", "discord.js" ], - "author": "Abheek Dhawan&Tejas Chugh", + "author": "Abheek Dhawan", "license": "MIT", "description": "A simple Discord bot that automatically generates Science Bowl rounds using the ScibowlDB API!" } diff --git a/src/commands/score.ts b/src/commands/score.ts new file mode 100644 index 0000000..c8f3db1 --- /dev/null +++ b/src/commands/score.ts @@ -0,0 +1,40 @@ +import { SlashCommandBuilder } from '@discordjs/builders'; +import { MessageEmbed } from 'discord.js'; + +import log from '../helpers/log'; +import userScore from '../models/userScore'; + +export const data = new SlashCommandBuilder() + .setName('score') + .setDescription('Returns the score of the current user or another') + .addUserOption(option => { + option + .setName('user') + .setDescription('The user to find the score for') + .setRequired(false); + + return option; + }); + +export async function execute(interaction) { + const scoreEmbed = new MessageEmbed() + .setColor('#ffffff'); + + const user = interaction.options.getUser('user') || interaction.user; + userScore.findOne({ authorID: user.id }, async (err, score) => { + if (err) { + log({ logger: 'db', content: `Unable to obtain user: ${err}`, level: 'info' }); + } + + if (!score) { + await interaction.reply({ content: 'Unfortunately, that user does not seem to have used AwesomeSciBo yet.', ephemeral: true }); + return; + } + + scoreEmbed + .setAuthor({ name: user.tag, iconURL: user.displayAvatarURL(true) }) + .setDescription(`Score: \`${score.score}\``); + + await interaction.reply({ embeds: [scoreEmbed] }); + }); +} diff --git a/src/commands/train.ts b/src/commands/train.ts index c95dc67..ff1227b 100644 --- a/src/commands/train.ts +++ b/src/commands/train.ts @@ -145,26 +145,33 @@ export async function execute(interaction) { .setDescription('It seems your answer was incorrect. Please react with <:override:955265585086857236> to override your answer if you think you got it right.') .setColor('#ffffff') .setTimestamp(); + const overrideButton = new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId('override') + .setEmoji('<:override:955265585086857236>') + .setStyle('SECONDARY'), + ); answerMsg.channel.send({ embeds: [overrideEmbed], + components: [overrideButton], }) .then(overrideMsg => { - overrideMsg.react('<:override:955265585086857236>'); - const filter = (reaction, user) => { + const overrideFilter = i => { return ( - ['override'].includes(reaction.emoji.name) && - user.id === answerMsg.author.id + ['override'].includes(i.customId) && + i.user.id === answerMsg.author.id ); }; overrideMsg - .awaitReactions({ - filter: filter, - max: 1, + .awaitMessageComponent({ + filter: overrideFilter, }) - .then(() => { - updateScore(true, score, authorId).then((msgToReply) => - answerMsg.reply(msgToReply), - ); + .then(i => { + updateScore(true, score, authorId).then(async msgToReply => { + await i.reply(msgToReply); + overrideMsg.edit({ components: [] }); + }); }).catch(err => log({ logger: 'train', content: `Failed to override score: ${err}`, level: 'error' })); }).catch(err => log({ logger: 'train', content: `Failed to send override message: ${err}`, level: 'error' })); } diff --git a/src/deploy-commands.ts b/src/deploy-commands.js old mode 100755 new mode 100644 similarity index 56% rename from src/deploy-commands.ts rename to src/deploy-commands.js index 359ac5c..0b7b816 --- a/src/deploy-commands.ts +++ b/src/deploy-commands.js @@ -1,18 +1,16 @@ #!/usr/bin/env node -import fs from 'node:fs'; -import { REST } from '@discordjs/rest'; -import { Routes } from 'discord-api-types/v9'; -import { clientId, token } from './helpers/env'; +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 : any[] = []; +const commands = []; const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); for (const file of commandFiles) { - import(`./commands/${file}`) - .then(command => { - commands.push(command.data.toJSON()); - }); + const command = require(`./commands/${file}`); + commands.push(command.data.toJSON()); } const rest = new REST({ version: '9' }).setToken(token); diff --git a/src/helpers/db.ts b/src/helpers/db.ts index afd7952..fac2f83 100644 --- a/src/helpers/db.ts +++ b/src/helpers/db.ts @@ -14,11 +14,14 @@ export async function updateScore(isCorrect, score, authorId) { authorID: authorId, score: score, }); - newUserScore.save((err) => - err - ? console.log('Error creating new user for scoring') - : console.log('Sucessfully created user to score.'), - ); + newUserScore.save(err => { + if (err) { + log({ logger: 'db', content: `Error creating new user ${authorId} for scoring`, level: 'error' }); + } + else { + log({ logger: 'db', content: `Successfully created user ${authorId} for scoring`, level: 'debug' }); + } + }); } else { // TODO: Error handling @@ -41,4 +44,4 @@ export async function connect(mongoUri) { }) .then(() => log({ logger: 'db', content: `Connected to the database at ${mongoUri}!`, level: 'info' })) .catch(err => log({ logger: 'db', content: `Failed to connect to the database at ${mongoUri}: ${err}`, level: 'fatal' })); -} \ No newline at end of file +} diff --git a/src/helpers/env.ts b/src/helpers/env.ts index 22b1b3d..c339592 100644 --- a/src/helpers/env.ts +++ b/src/helpers/env.ts @@ -1,6 +1,6 @@ import 'dotenv/config'; -export const clientId : string = process.env.CLIENT_ID!; -export const testingGuild : string = process.env.TESTING_GUILD!; -export const token : string = process.env.TOKEN!; -export const mongoUri : string = process.env.MONGO_URI!; \ No newline at end of file +export const clientId : string = process.env.CLIENT_ID || ''; +export const testingGuild : string = process.env.TESTING_GUILD || ''; +export const token : string = process.env.TOKEN || ''; +export const mongoUri : string = process.env.MONGO_URI || 'mongodb://mongo:27017/awesome'; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index cf9211b..63f9120 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -37,7 +37,7 @@ // "noResolve": true, /* Disallow `import`s, `require`s or `