From e2ffaf4cc0c809e62e1ba6b0e7c225cdccc8983f Mon Sep 17 00:00:00 2001 From: GalvinPython <77013913+GalvinPython@users.noreply.github.com> Date: Sun, 11 Aug 2024 20:44:02 +0100 Subject: [PATCH] feat(bot): added hourly leaderboard updates also tried messing around with eslint - never again --- .eslintrc.json | 56 ++++++++++++++++++++ api/src/db/queries/updates.ts | 18 +++++++ api/src/index.ts | 13 ++++- bot/package.json | 1 + bot/src/commands.ts | 38 ++----------- bot/src/events/ready.ts | 5 ++ bot/src/utils/leaderboardEmbed.ts | 41 ++++++++++++++ bot/src/utils/quickEmbed.ts | 2 +- bot/src/utils/requestAPI.ts | 16 +++++- bot/src/utils/sendAutoUpdates.ts | 15 ++++++ bun.lockb | Bin 476696 -> 476224 bytes package-lock.json | 62 +++++----------------- package.json | 5 +- web/components/navbar.tsx | 3 -- web/components/theme-switch.tsx | 85 ------------------------------ web/postcss.config.js | 10 ++-- 16 files changed, 188 insertions(+), 182 deletions(-) create mode 100644 .eslintrc.json create mode 100644 bot/src/utils/leaderboardEmbed.ts create mode 100644 bot/src/utils/sendAutoUpdates.ts delete mode 100644 web/components/theme-switch.tsx diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..f4efc2c --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,56 @@ +{ + "extends": "eslint:recommended", + "env": { + "node": true, + "es6": true + }, + "parserOptions": { + "sourceType": "module", + "ecmaVersion": "latest" + }, + "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/api/src/db/queries/updates.ts b/api/src/db/queries/updates.ts index 80bfdbc..8c5c296 100644 --- a/api/src/db/queries/updates.ts +++ b/api/src/db/queries/updates.ts @@ -48,6 +48,7 @@ export async function disableUpdates(guildId: string): Promise<[QueryError | nul } export async function setUpdatesChannel(guildId: string, channelId: string | null): Promise<[QueryError | null, boolean]> { + console.log("Setting updates channel", guildId, channelId); return new Promise((resolve, reject) => { pool.query( ` @@ -67,3 +68,20 @@ export async function setUpdatesChannel(guildId: string, channelId: string | nul ); }); } + +export async function getAllServersWithUpdatesEnabled(): Promise<[QueryError | null, Updates[]]> { + return new Promise((resolve, reject) => { + pool.query( + ` + SELECT id, updates_channel_id, updates_enabled FROM guilds WHERE updates_enabled = TRUE + `, + (err, results) => { + if (err) { + reject([err, []]); + } else { + resolve([null, results as Updates[]]); + } + }, + ); + }); +} \ No newline at end of file diff --git a/api/src/index.ts b/api/src/index.ts index aefd016..f02193b 100644 --- a/api/src/index.ts +++ b/api/src/index.ts @@ -1,6 +1,6 @@ import express, { type NextFunction, type Request, type Response } from "express"; import cors from "cors"; -import { getBotInfo, getGuild, getUser, getUsers, initTables, pool, updateGuild, enableUpdates, disableUpdates, setCooldown, setUpdatesChannel, setXP, setLevel, removeGuild, removeUser } from "./db"; +import { getBotInfo, getGuild, getUser, getUsers, initTables, pool, updateGuild, enableUpdates, disableUpdates, setCooldown, setUpdatesChannel, setXP, setLevel, removeGuild, removeUser, getAllServersWithUpdatesEnabled } from "./db"; const app = express(); const PORT = 18103; @@ -295,6 +295,17 @@ app.post("/admin/:action/:guild/:target", authMiddleware, async (req, res) => { return res.status(500).json({ message: 'Internal server error', err }); } default: + if (guild == "all") { + try { + const [err, data] = await getAllServersWithUpdatesEnabled(); + if (err) { + return res.status(500).json({ message: "Internal server error", err }); + } + return res.status(200).json(data); + } catch (error) { + return res.status(500).json({ message: "Internal server error" }); + } + } try { const [err, data] = await getGuild(guild); if (err) { diff --git a/bot/package.json b/bot/package.json index 11e6a0f..fc76c1f 100644 --- a/bot/package.json +++ b/bot/package.json @@ -9,6 +9,7 @@ "dependencies": { "canvacord": "^6.0.2", "colorthief": "^2.4.0", + "cron": "^3.1.7", "discord.js": "^14.15.3" }, "devDependencies": { diff --git a/bot/src/commands.ts b/bot/src/commands.ts index e94c744..d55d44f 100644 --- a/bot/src/commands.ts +++ b/bot/src/commands.ts @@ -7,6 +7,7 @@ import { getGuildLeaderboard, makeGETRequest, getRoles, removeRole, addRole, ena import convertToLevels from './utils/convertToLevels'; import quickEmbed from './utils/quickEmbed'; import { Font, RankCardBuilder } from 'canvacord'; +import leaderboardEmbed from './utils/leaderboardEmbed'; Font.loadDefault(); @@ -273,41 +274,8 @@ const commands: Record = { const guild = interaction.guild?.id; try { - const leaderboard = await getGuildLeaderboard(guild as string); - - if (leaderboard.length === 0) { - await interaction.reply('No leaderboard data available.'); - return; - } - - // Create a new embed using the custom embed function - const leaderboardEmbed = quickEmbed({ - color: 'Blurple', - title: `Leaderboard for ${interaction.guild?.name}`, - description: 'Top 10 Users' - }, interaction); - - // Add a field for each user with a mention - leaderboard.leaderboard.slice(0, 10).forEach((entry: { id: string; xp: number; }, index: number) => { - leaderboardEmbed.addFields([ - { - name: `${index + 1}.`, - value: `<@${entry.id}>: ${entry.xp.toLocaleString("en-US")} XP`, - inline: false - } - ]); - }); - - const button = new ButtonBuilder() - .setLabel('Leaderboard') - .setURL(`https://chatr.imgalvin.me/leaderboard/${interaction.guildId}`) - .setStyle(ButtonStyle.Link); - - const row = new ActionRowBuilder() - .addComponents(button); - - // Send the embed - await interaction.reply({ embeds: [leaderboardEmbed], components: [row] }); + const [embed, row] = await leaderboardEmbed(guild as string, interaction); + await interaction.reply({ embeds: [embed], components: [row] }); } catch (error) { console.error('Error executing command:', error); await interaction.reply('There was an error retrieving the leaderboard.'); diff --git a/bot/src/events/ready.ts b/bot/src/events/ready.ts index 27891c3..0230b06 100644 --- a/bot/src/events/ready.ts +++ b/bot/src/events/ready.ts @@ -1,5 +1,7 @@ import { ActivityType, Events, PresenceUpdateStatus } from 'discord.js'; import client from '../index'; +import cron from 'cron'; +import sendAutoUpdates from '../utils/sendAutoUpdates'; // update the bot's presence function updatePresence() { @@ -19,6 +21,9 @@ function updatePresence() { client.once(Events.ClientReady, async (bot) => { console.log(`Ready! Logged in as ${bot.user?.tag}`); updatePresence(); + // Create a cron job to update the server count in the status every minute + const job = new cron.CronJob('0 * * * *', sendAutoUpdates); + job.start(); }); // Update the server count in the status every minute diff --git a/bot/src/utils/leaderboardEmbed.ts b/bot/src/utils/leaderboardEmbed.ts new file mode 100644 index 0000000..2267acd --- /dev/null +++ b/bot/src/utils/leaderboardEmbed.ts @@ -0,0 +1,41 @@ +import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js"; +import quickEmbed from "./quickEmbed"; +import { getGuildLeaderboard } from "./requestAPI"; +import client from ".."; + +export default async function (guild: string, interaction?: any) { + const leaderboard = await getGuildLeaderboard(guild); + + if (leaderboard.length === 0) { + await interaction.reply('No leaderboard data available.'); + return; + } + + // Create a new embed using the custom embed function + const leaderboardEmbed = quickEmbed({ + color: 'Blurple', + title: `Leaderboard for ${interaction ? interaction.guild?.name : (await client.guilds.fetch(guild)).name}`, + description: 'Top 10 Users' + }, interaction); + + // Add a field for each user with a mention + leaderboard.leaderboard.slice(0, 10).forEach((entry: { id: string; xp: number; }, index: number) => { + leaderboardEmbed.addFields([ + { + name: `${index + 1}.`, + value: `<@${entry.id}>: ${entry.xp.toLocaleString("en-US")} XP`, + inline: false + } + ]); + }); + + const button = new ButtonBuilder() + .setLabel('Leaderboard') + .setURL(`https://chatr.fun/leaderboard/${guild}`) + .setStyle(ButtonStyle.Link); + + const row = new ActionRowBuilder() + .addComponents(button); + + return [leaderboardEmbed, row]; +} \ No newline at end of file diff --git a/bot/src/utils/quickEmbed.ts b/bot/src/utils/quickEmbed.ts index 30c306f..a313a6b 100644 --- a/bot/src/utils/quickEmbed.ts +++ b/bot/src/utils/quickEmbed.ts @@ -14,7 +14,7 @@ export default function ( text: interaction?.client.user.displayName ?? client?.user?.displayName ?? - 'No name', + 'Chatr', iconURL: interaction?.client?.user?.avatarURL() ?? client?.user?.avatarURL() ?? diff --git a/bot/src/utils/requestAPI.ts b/bot/src/utils/requestAPI.ts index 065c2ef..e5b50b4 100644 --- a/bot/src/utils/requestAPI.ts +++ b/bot/src/utils/requestAPI.ts @@ -210,12 +210,24 @@ export async function disableUpdates(guild: string) { }); return response.status === 200; } + +export async function getAllGuildsWithUpdatesEnabled() { + const response = await fetch(`http://localhost:18103/admin/updates/all/get`, { + "headers": { + 'Content-Type': 'application/json', + 'Authorization': process.env.AUTH as string, + }, + "body": JSON.stringify({}), + "method": "POST" + }); + return response.json(); +} //#endregion //#region Cooldowns export async function getCooldown(guild: string) { const response = await fetch(`http://localhost:18103/admin/cooldown/${guild}/get`, { - "headers": { + "headers": { 'Content-Type': 'application/json', 'Authorization': process.env.AUTH as string, }, @@ -228,7 +240,7 @@ export async function getCooldown(guild: string) { export async function setCooldown(guild: string, cooldown: number) { const response = await fetch(`http://localhost:18103/admin/cooldown/${guild}/set`, { "headers": { - 'Content-Type': 'application/json', + 'Content-Type': 'application/json', 'Authorization': process.env.AUTH as string, }, "body": JSON.stringify({ extraData: { cooldown } }), diff --git a/bot/src/utils/sendAutoUpdates.ts b/bot/src/utils/sendAutoUpdates.ts new file mode 100644 index 0000000..30d41e0 --- /dev/null +++ b/bot/src/utils/sendAutoUpdates.ts @@ -0,0 +1,15 @@ +import type { TextChannel } from "discord.js"; +import client from ".."; +import leaderboardEmbed from "./leaderboardEmbed"; +import { getAllGuildsWithUpdatesEnabled } from "./requestAPI"; + +export default async function () { + const allGuildsData = await getAllGuildsWithUpdatesEnabled() + + // TODO: Type guild + allGuildsData.forEach(async (guild: any) => { + const [embed, row] = await leaderboardEmbed(guild.id) + const channel = await client.channels.fetch(guild.updates_channel_id) as TextChannel; + await channel?.send({ embeds: [embed], components: [row] }); + }) +} \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 7ba122e8f8738a493db34989699f739748843b0c..27f66c1f92167cf3a70b5057ca57a9637470991c 100755 GIT binary patch delta 32497 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 f^~-15HwZ{nvu diff --git a/package-lock.json b/package-lock.json index e2e8574..c70f27f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,9 +17,10 @@ "@types/bun": "latest", "@types/eslint__js": "^8.42.3", "dotenv-cli": "^7.4.2", + "eslint": "^8.56.0", "eslint-config-neon": "^0.1.62", "turbo": "^2.0.9", - "typescript-eslint": "^7.16.1" + "typescript-eslint": "^7.0.1" }, "peerDependencies": { "typescript": "^5.0.0" @@ -47,6 +48,7 @@ "dependencies": { "canvacord": "^6.0.2", "colorthief": "^2.4.0", + "cron": "^3.1.7", "discord.js": "^14.15.3" }, "devDependencies": { @@ -1124,7 +1126,6 @@ "version": "0.11.14", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.2", "debug": "^4.3.1", @@ -1138,7 +1139,6 @@ "version": "4.3.5", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -1154,14 +1154,12 @@ "node_modules/@humanwhocodes/config-array/node_modules/debug/node_modules/ms": { "version": "2.1.2", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=12.22" }, @@ -1173,8 +1171,7 @@ "node_modules/@humanwhocodes/object-schema": { "version": "2.0.3", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@internationalized/date": { "version": "3.5.4", @@ -5313,8 +5310,7 @@ "node_modules/@ungap/structured-clone": { "version": "1.2.0", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/@vladfrangu/async_event_emitter": { "version": "2.2.4", @@ -6586,8 +6582,7 @@ "node_modules/deep-is": { "version": "0.1.4", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", @@ -7044,7 +7039,6 @@ "version": "8.57.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -7992,7 +7986,6 @@ "version": "8.57.0", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -8001,7 +7994,6 @@ "version": "4.3.5", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ms": "2.1.2" }, @@ -8017,14 +8009,12 @@ "node_modules/eslint/node_modules/debug/node_modules/ms": { "version": "2.1.2", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -8040,7 +8030,6 @@ "version": "13.24.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -8220,8 +8209,7 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fastq": { "version": "1.17.1", @@ -8238,7 +8226,6 @@ "version": "6.0.1", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -8291,7 +8278,6 @@ "version": "5.0.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -8314,7 +8300,6 @@ "version": "3.2.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -8327,8 +8312,7 @@ "node_modules/flatted": { "version": "3.3.1", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/for-each": { "version": "0.3.3", @@ -8869,7 +8853,6 @@ "version": "0.1.4", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.8.19" } @@ -9240,7 +9223,6 @@ "version": "3.0.3", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -9493,8 +9475,7 @@ "node_modules/json-buffer": { "version": "3.0.1", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "3.0.2", @@ -9515,8 +9496,7 @@ "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -9553,7 +9533,6 @@ "version": "4.5.4", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "json-buffer": "3.0.1" } @@ -9586,7 +9565,6 @@ "version": "0.4.1", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -9631,7 +9609,6 @@ "version": "6.0.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -9669,8 +9646,7 @@ "node_modules/lodash.merge": { "version": "4.6.2", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.omit": { "version": "4.5.0", @@ -11126,7 +11102,6 @@ "version": "0.9.4", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -11143,7 +11118,6 @@ "version": "3.1.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -11158,7 +11132,6 @@ "version": "5.0.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -11559,7 +11532,6 @@ "version": "1.2.1", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8.0" } @@ -12206,7 +12178,6 @@ "version": "3.0.2", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -12221,7 +12192,6 @@ "version": "7.2.3", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -13109,8 +13079,7 @@ "node_modules/text-table": { "version": "0.2.0", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/thenify": { "version": "3.3.1", @@ -13302,7 +13271,6 @@ "version": "0.4.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -14136,7 +14104,6 @@ "version": "1.2.5", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -14333,7 +14300,6 @@ "version": "0.1.0", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 756aa4a..02806bc 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "scripts": { "dev": "turbo run dev", - "lint": "eslint . --config eslint.config.mjs", + "lint": "eslint .", "build": "cd web && bun run build" }, "devDependencies": { @@ -18,9 +18,10 @@ "@types/bun": "latest", "@types/eslint__js": "^8.42.3", "dotenv-cli": "^7.4.2", + "eslint": "^8.56.0", "eslint-config-neon": "^0.1.62", "turbo": "^2.0.9", - "typescript-eslint": "^7.16.1" + "typescript-eslint": "^7.0.1" }, "peerDependencies": { "typescript": "^5.0.0" diff --git a/web/components/navbar.tsx b/web/components/navbar.tsx index f6aef7e..44e8efa 100644 --- a/web/components/navbar.tsx +++ b/web/components/navbar.tsx @@ -15,7 +15,6 @@ import { siteConfig } from "@/config/site"; import NextLink from "next/link"; import clsx from "clsx"; -import { ThemeSwitch } from "@/components/theme-switch"; import { TwitterIcon, GithubIcon, @@ -60,7 +59,6 @@ export const Navbar = () => { - {/*