commit 0f79d614918bba1fa0c7876a4052574dcff02063 Author: Skylar Grant Date: Thu Feb 9 23:25:25 2023 -0500 Initial commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..163b5f6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +npm-debug.log +env.dev +env.prod +.env \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..ae431cc --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,49 @@ +{ + "extends": "eslint:recommended", + "env": { + "node": true, + "es6": true + }, + "parserOptions": { + "ecmaVersion": 2021 + }, + "rules": { + "arrow-spacing": ["warn", { "before": true, "after": true }], + "brace-style": ["error", "stroustrup", { "allowSingleLine": true }], + "comma-dangle": ["error", "always-multiline"], + "comma-spacing": "error", + "comma-style": "error", + "curly": ["error", "multi-line", "consistent"], + "dot-location": ["error", "property"], + "handle-callback-err": "off", + "indent": ["error", "tab"], + "keyword-spacing": "error", + "max-nested-callbacks": ["error", { "max": 4 }], + "max-statements-per-line": ["error", { "max": 2 }], + "no-console": "off", + "no-empty-function": "error", + "no-floating-decimal": "error", + "no-inline-comments": "error", + "no-lonely-if": "error", + "no-multi-spaces": "error", + "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }], + "no-shadow": ["error", { "allow": ["err", "resolve", "reject"] }], + "no-trailing-spaces": ["error"], + "no-var": "error", + "object-curly-spacing": ["error", "always"], + "prefer-const": "error", + "quotes": ["error", "single"], + "semi": ["error", "always"], + "space-before-blocks": "error", + "space-before-function-paren": ["error", { + "anonymous": "never", + "named": "never", + "asyncArrow": "always" + }], + "space-in-parens": "error", + "space-infix-ops": "error", + "space-unary-ops": "error", + "spaced-comment": "error", + "yoda": "error" + } +} \ No newline at end of file diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..5f27b9d --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,26 @@ +name: Docker Image CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +env: + DHUB_UNAME: ${{ secrets.DHUB_UNAME }} + DHUB_PWORD: ${{ secrets.DHUB_PWORD }} + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build the Docker image + run: docker build . --file Dockerfile --tag v0idf1sh/treeanalyzer + - name: Log into Docker Hub + run: docker login -u $DHUB_UNAME -p $DHUB_PWORD + - name: Push image to Docker Hub + run: docker push v0idf1sh/treeanalyzer diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..923ffd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,118 @@ +# IDE Config Files +.vscode +package-lock.json +.VSCodeCounter/ +env.dev +env.prod +.DS_Store + +# Custom folders +# gifs/* +# pastas/* + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env.dev +.env.prod + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a0b785a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM node:16 +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +COPY package.json ./ +RUN npm install +COPY . . +CMD [ "node", "main.js" ] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e49c919 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Discord Bot Template +This is a very basic Discord.js v14 bot template. This is meant to be an easy jumping-off point for quick bot creation without having to set up the basics every time. \ No newline at end of file diff --git a/data/config.json b/data/config.json new file mode 100644 index 0000000..05eb669 --- /dev/null +++ b/data/config.json @@ -0,0 +1,4 @@ +{ + "guildId": "", + "validCommands": [] +} \ No newline at end of file diff --git a/data/strings.json b/data/strings.json new file mode 100644 index 0000000..6f3f0e9 --- /dev/null +++ b/data/strings.json @@ -0,0 +1,21 @@ +{ + "help": { + "info": "", + "setup": "", + "permissions": "" + }, + "embeds": { + "footer": "", + "color": "0x55FF55" + }, + "emoji": { + "next": "⏭️", + "previous": "⏮️", + "confirm": "☑️", + "cancel": "❌" + }, + "urls": { + "avatar": "" + }, + "temp": {} +} \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..dc55716 --- /dev/null +++ b/main.js @@ -0,0 +1,55 @@ +/* eslint-disable no-case-declarations */ +/* eslint-disable indent */ +// dotenv for handling environment variables +const dotenv = require('dotenv'); +dotenv.config(); +const token = process.env.TOKEN; +const statusChannelId = process.env.statusChannelId; + +// Discord.JS +const { Client, GatewayIntentBits, Partials } = require('discord.js'); +const client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.GuildMessageReactions, + GatewayIntentBits.MessageContent + ], + partials: [ + Partials.Channel, + Partials.Message + ], +}); + +// Various imports +const fn = require('./modules/functions.js'); +const strings = require('./data/strings.json'); +const isDev = process.env.isDev; + +client.once('ready', () => { + fn.collections.slashCommands(client); + console.log('Ready!'); + client.channels.fetch(statusChannelId).then(channel => { + channel.send(`${new Date().toISOString()} -- Ready`); + }); +}); + +// slash-commands +client.on('interactionCreate', async interaction => { + if (interaction.isCommand()) { + const { commandName } = interaction; + + if (client.slashCommands.has(commandName)) { + client.slashCommands.get(commandName).execute(interaction); + } else { + interaction.reply('Sorry, I don\'t have access to that command.'); + console.error('Slash command attempted to run but not found: /' + commandName); + } + } + + if (interaction.isButton() && interaction.component.customId == 'refresh') { + fn.refresh(interaction); + } +}); + +client.login(token); \ No newline at end of file diff --git a/modules/_clear-commands.js b/modules/_clear-commands.js new file mode 100644 index 0000000..57b7d64 --- /dev/null +++ b/modules/_clear-commands.js @@ -0,0 +1,27 @@ +// dotenv for handling environment variables +const dotenv = require('dotenv'); +dotenv.config(); + +const { REST } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v9'); +const clientId = process.env.clientId; +const { guildId } = require('../data/config.json'); +const token = process.env.TOKEN; + +const rest = new REST({ version: '9' }).setToken(token); + +(async () => { + try { + console.log('Started refreshing application (/) commands.'); + + await rest.put( + Routes.applicationGuildCommands(clientId, guildId), + { body: '' }, + ); + + console.log('Successfully reloaded application (/) commands.'); + process.exit(); + } catch (error) { + console.error(error); + } +})(); \ No newline at end of file diff --git a/modules/_deploy-commands.js b/modules/_deploy-commands.js new file mode 100644 index 0000000..933b61f --- /dev/null +++ b/modules/_deploy-commands.js @@ -0,0 +1,39 @@ +// dotenv for handling environment variables +const dotenv = require('dotenv'); +dotenv.config(); + +const { REST, Routes } = require('discord.js'); +const { guildId } = require('../data/config.json'); +const clientId = process.env.clientId; +const token = process.env.TOKEN; +const fs = require('fs'); + +const commands = []; +const commandFiles = fs.readdirSync('../slash-commands').filter(file => file.endsWith('.js')); + +for (const file of commandFiles) { + const command = require(`../slash-commands/${file}`); + if (command.data != undefined) { + commands.push(command.data.toJSON()); + } +} + +console.log(commands); + +const rest = new REST({ version: '10' }).setToken(token); + +(async () => { + try { + console.log('Started refreshing application (/) commands.'); + + await rest.put( + Routes.applicationGuildCommands(clientId, guildId), + { body: commands }, + ); + + console.log('Successfully reloaded application (/) commands.'); + process.exit(); + } catch (error) { + console.error(error); + } +})(); \ No newline at end of file diff --git a/modules/_deploy-global.js b/modules/_deploy-global.js new file mode 100644 index 0000000..cd7b8ce --- /dev/null +++ b/modules/_deploy-global.js @@ -0,0 +1,39 @@ +// dotenv for handling environment variables +const dotenv = require('dotenv'); +dotenv.config(); + +const { REST } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v9'); +const clientId = process.env.clientId; +const token = process.env.TOKEN; +const fs = require('fs'); + +const commands = []; +const commandFiles = fs.readdirSync('./slash-commands').filter(file => file.endsWith('.js')); + +for (const file of commandFiles) { + const command = require(`./slash-commands/${file}`); + if (command.data != undefined) { + commands.push(command.data.toJSON()); + } +} + +console.log(commands); + +const rest = new REST({ version: '9' }).setToken(token); + +(async () => { + try { + console.log('Started refreshing application (/) commands.'); + + await rest.put( + Routes.applicationCommands(clientId), + { body: commands }, + ); + + console.log('Successfully reloaded application (/) commands.'); + process.exit(); + } catch (error) { + console.error(error); + } +})(); \ No newline at end of file diff --git a/modules/functions.js b/modules/functions.js new file mode 100644 index 0000000..f3edb7f --- /dev/null +++ b/modules/functions.js @@ -0,0 +1,93 @@ +/* eslint-disable comma-dangle */ +// dotenv for handling environment variables +const dotenv = require('dotenv'); +dotenv.config(); +const isDev = process.env.isDev; + +// filesystem +const fs = require('fs'); + +// Discord.js +const Discord = require('discord.js'); +const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = Discord; + +// Various imports from other files +const config = require('../data/config.json'); +let guildInfo = require('../data/guildInfo.json'); +const strings = require('../data/strings.json'); +const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js')); + +const functions = { + // Functions for managing and creating Collections + collections: { + // Create the collection of slash commands + slashCommands(client) { + if (!client.slashCommands) client.slashCommands = new Discord.Collection(); + client.slashCommands.clear(); + for (const file of slashCommandFiles) { + const slashCommand = require(`../slash-commands/${file}`); + if (slashCommand.data != undefined) { + client.slashCommands.set(slashCommand.data.name, slashCommand); + } + } + if (isDev) console.log('Slash Commands Collection Built'); + } + }, + builders: { + refreshAction() { + // Create the button to go in the Action Row + const refreshButton = new ButtonBuilder() + .setCustomId('refresh') + .setLabel('Refresh') + .setStyle(ButtonStyle.Primary); + // Create the Action Row with the Button in it, to be sent with the Embed + const refreshActionRow = new ActionRowBuilder() + .addComponents( + refreshButton + ); + return refreshActionRow; + }, + helpEmbed(content, private) { + const embed = new EmbedBuilder() + .setColor(strings.embeds.color) + .setTitle('Grow A Tree Analyzer Help') + .setDescription(content) + .setFooter({ text: strings.embeds.footer }); + const privateBool = private == 'true'; + const messageContents = { embeds: [embed], ephemeral: privateBool }; + return messageContents; + }, + errorEmbed(content) { + const embed = new EmbedBuilder() + .setColor(0xFF0000) + .setTitle('Error!') + .setDescription(content) + .setFooter({ text: strings.embeds.footer }); + const messageContents = { embeds: [embed], ephemeral: true }; + return messageContents; + }, + embed(content) { + const embed = new EmbedBuilder() + .setColor(0x8888FF) + .setTitle('Information') + .setDescription(content) + .setFooter({ text: strings.embeds.footer }); + const messageContents = { embeds: [embed], ephemeral: true }; + return messageContents; + } + }, + refresh(interaction) { + functions.rankings.parse(interaction).then(r1 => { + functions.tree.parse(interaction).then(r2 => { + const embed = functions.builders.comparisonEmbed(functions.rankings.compare(interaction), functions.builders.refreshAction()) + interaction.update(embed); + }).catch(e => { + interaction.reply(functions.builders.errorEmbed(e)); + }); + }).catch(e => { + interaction.reply(functions.builders.errorEmbed(e)); + }); + } +}; + +module.exports = functions; \ No newline at end of file diff --git a/slash-commands/template b/slash-commands/template new file mode 100644 index 0000000..774cf03 --- /dev/null +++ b/slash-commands/template @@ -0,0 +1,11 @@ +const { SlashCommandBuilder } = require('discord.js'); +const fn = require('../modules/functions.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('') + .setDescription(''), + async execute(interaction) { + await + }, +}; \ No newline at end of file