diff --git a/api/db/index.ts b/api/db/index.ts
new file mode 100644
index 0000000..cd01b1d
--- /dev/null
+++ b/api/db/index.ts
@@ -0,0 +1,14 @@
+import mysql from "mysql2";
+
+// Create a MySQL connection pool
+export const pool = mysql.createPool({
+ host: process.env.MYSQL_ADDRESS as string,
+ port: parseInt(process.env.MYSQL_PORT as string),
+ user: process.env.MYSQL_USER as string,
+ password: process.env.MYSQL_PASSWORD as string,
+ database: process.env.MYSQL_DATABASE as string,
+});
+
+export * from './init';
+export * from './queries/guilds';
+export * from './queries/users';
diff --git a/api/db/init.ts b/api/db/init.ts
new file mode 100644
index 0000000..14e121c
--- /dev/null
+++ b/api/db/init.ts
@@ -0,0 +1,79 @@
+import { pool } from ".";
+
+export async function initTables() {
+ const createGuildsTable = `
+ CREATE TABLE IF NOT EXISTS guilds (
+ id VARCHAR(255) NOT NULL PRIMARY KEY,
+ name VARCHAR(255),
+ icon VARCHAR(255),
+ members INT,
+ updates_enabled BOOLEAN DEFAULT FALSE,
+ updates_channel JSON
+ )
+ `;
+ const createUsersTable = `
+ CREATE TABLE IF NOT EXISTS users (
+ id VARCHAR(255) NOT NULL,
+ guild_id VARCHAR(255) NOT NULL,
+ name VARCHAR(255),
+ nickname VARCHAR(255),
+ pfp VARCHAR(255),
+ xp INT DEFAULT 0,
+ level INT DEFAULT 0,
+ xp_needed_next_level INT,
+ progress_next_level DECIMAL(6, 2),
+ PRIMARY KEY (id, guild_id),
+ FOREIGN KEY (guild_id) REFERENCES guilds(id)
+ )
+ `;
+ const createRolesTable = `
+ CREATE TABLE IF NOT EXISTS roles (
+ id VARCHAR(255) NOT NULL PRIMARY KEY,
+ guild_id VARCHAR(255) NOT NULL,
+ name VARCHAR(255),
+ level INT NOT NULL,
+ FOREIGN KEY (guild_id) REFERENCES guilds(id)
+ )
+ `
+ const createUpdatesTable = `
+ CREATE TABLE IF NOT EXISTS updates (
+ guild_id VARCHAR(255) NOT NULL PRIMARY KEY,
+ channel_id VARCHAR(255) NOT NULL,
+ enabled BOOLEAN DEFAULT FALSE,
+ FOREIGN KEY (guild_id) REFERENCES guilds(id)
+ )
+ `
+
+ pool.query(createGuildsTable, (err, results) => {
+ if (err) {
+ console.error("Error creating guilds table:", err);
+ } else {
+ console.log("Guilds table created:", results);
+ }
+ });
+
+ pool.query(createUsersTable, (err, results) => {
+ if (err) {
+ console.error("Error creating users table:", err);
+ } else {
+ console.log("Users table created:", results);
+ }
+ });
+
+
+ pool.query(createRolesTable, (err, results) => {
+ if (err) {
+ console.error("Error creating roles table:", err);
+ } else {
+ console.log("Roles table created:", results);
+ }
+ });
+
+ pool.query(createUpdatesTable, (err, results) => {
+ if (err) {
+ console.error("Error creating updates table:", err);
+ } else {
+ console.log("Updates table created:", results);
+ }
+ });
+}
diff --git a/api/db/queries/guilds.ts b/api/db/queries/guilds.ts
new file mode 100644
index 0000000..1b6ed93
--- /dev/null
+++ b/api/db/queries/guilds.ts
@@ -0,0 +1,75 @@
+import type { QueryError } from "mysql2";
+import { pool } from "..";
+
+export interface Guild {
+ id: string;
+ name: string;
+ icon: string;
+ members: number;
+ updates_enabled: boolean;
+ updates_channel: string;
+}
+
+export async function getGuild(guildId: string): Promise<[QueryError | null, Guild | null]> {
+ return new Promise((resolve, reject) => {
+ pool.query("SELECT * FROM guilds WHERE id = ?", [guildId], (err, results) => {
+ if (err) {
+ reject([err, null]);
+ } else {
+ resolve([null, (results as Guild[])[0]]);
+ }
+ });
+ });
+}
+
+export async function updateGuild(guild: Guild): Promise<[QueryError, null] | [null, Guild[]]> {
+ return new Promise((resolve, reject) => {
+ pool.query(
+ `
+ INSERT INTO guilds (id, name, icon, members, updates_enabled, updates_channel)
+ VALUES (?, ?, ?, ?, ?, ?)
+ ON DUPLICATE KEY UPDATE
+ name = VALUES(name),
+ icon = VALUES(icon),
+ members = VALUES(members),
+ updates_enabled = VALUES(updates_enabled),
+ updates_channel = VALUES(updates_channel)
+ `,
+ [
+ guild.id,
+ guild.name,
+ guild.icon,
+ guild.members,
+ guild.updates_enabled,
+ guild.updates_channel,
+ ],
+ (err, results) => {
+ if (err) {
+ reject([err, null]);
+ } else {
+ resolve([null, results as Guild[]]);
+ }
+ },
+ );
+ });
+}
+
+interface BotInfo {
+ total_guilds: number;
+ total_members: number;
+}
+
+export async function getBotInfo(): Promise<[QueryError | null, BotInfo | null]> {
+ return new Promise((resolve, reject) => {
+ pool.query("SELECT COUNT(*) AS total_guilds, SUM(members) AS total_members FROM guilds", (err, results) => {
+ if (err) {
+ reject([err, null]);
+ } else {
+ resolve([null, {
+ total_guilds: (results as BotInfo[])[0].total_guilds,
+ total_members: (results as BotInfo[])[0].total_members ?? 0,
+ }]);
+ }
+ })
+ })
+}
diff --git a/api/db/queries/users.ts b/api/db/queries/users.ts
new file mode 100644
index 0000000..b3cc2e3
--- /dev/null
+++ b/api/db/queries/users.ts
@@ -0,0 +1,38 @@
+import type { QueryError } from "mysql2";
+import { pool } from "..";
+
+export interface User {
+ id: string;
+ guild_id: string;
+ name: string;
+ nickname: string;
+ pfp: string;
+ xp: number;
+ level: number;
+ xp_needed_next_level: number;
+ progress_next_level: number;
+}
+
+export async function getUsers(guildId: string): Promise<[QueryError, null] | [null, User[]]> {
+ return new Promise((resolve, reject) => {
+ pool.query("SELECT * FROM users WHERE guild_id = ? ORDER BY xp DESC", [guildId], (err, results) => {
+ if (err) {
+ reject([err, null]);
+ } else {
+ resolve([null, (results as User[])]);
+ }
+ });
+ });
+}
+
+export async function getUser(userId: string, guildId: string): Promise<[QueryError, null] | [null, User | null]> {
+ return new Promise((resolve, reject) => {
+ pool.query("SELECT * FROM users WHERE id = ? AND guild_id = ?", [userId, guildId], (err, results) => {
+ if (err) {
+ reject([err, null]);
+ } else {
+ resolve([null, (results as User[])[0]]);
+ }
+ });
+ });
+}
diff --git a/api/index.ts b/api/index.ts
index ef57d6e..c9537d5 100644
--- a/api/index.ts
+++ b/api/index.ts
@@ -1,449 +1,291 @@
-import express from 'express';
-import cors from 'cors';
-import mysql from 'mysql2';
-import path from 'path';
+import express, { type NextFunction, type Request, type Response } from "express";
+import cors from "cors";
+import path from "path";
+import { getBotInfo, getGuild, getUser, getUsers, initTables, pool, updateGuild } from "./db";
const app = express();
const PORT = 18103;
app.use(cors());
app.use(express.json());
-app.use(express.static(path.join(__dirname, 'public')));
-app.set('view engine', 'ejs');
-app.set('views', path.join(__dirname, 'views'));
-
-// Create a MySQL connection pool
-const pool = mysql.createPool({
- host: process.env.MYSQL_ADDRESS as string,
- port: parseInt(process.env.MYSQL_PORT as string),
- user: process.env.MYSQL_USER as string,
- password: process.env.MYSQL_PASSWORD as string,
- database: process.env.MYSQL_DATABASE as string,
-});
-
-// Create the basic information tables
-async function initInfoTables() {
- const createUpdatesTable = `
- CREATE TABLE IF NOT EXISTS info_updates (
- guild_id VARCHAR(255) NOT NULL,
- enabled BOOLEAN DEFAULT FALSE,
- channel_id VARCHAR(255),
- PRIMARY KEY (guild_id)
- )
- `;
- const createRolesTable = `
- CREATE TABLE IF NOT EXISTS info_roles (
- guild_id VARCHAR(255) NOT NULL,
- role_id VARCHAR(255) NOT NULL,
- level INT NOT NULL,
- PRIMARY KEY (role_id)
- )
- `;
- const createExcludesTable = `
- CREATE TABLE IF NOT EXISTS info_excludes (
- channel_id VARCHAR(255) NOT NULL,
- guild_id VARCHAR(255) NOT NULL,
- PRIMARY KEY (channel_id)
- )
- `;
- const createGuildsTable = `
- CREATE TABLE IF NOT EXISTS info_guilds (
- guild_id VARCHAR(255) NOT NULL,
- guild_name VARCHAR(255),
- guild_icon VARCHAR(255),
- guild_members INT,
- PRIMARY KEY (guild_id)
- )
- `;
-
- pool.query(createUpdatesTable, (err, results) => {
- if (err) {
- console.error('Error creating updates table:', err);
- } else {
- console.log('Updates table created:', results);
- }
- });
-
- pool.query(createRolesTable, (err, results) => {
- if (err) {
- console.error('Error creating roles table:', err);
- } else {
- console.log('Roles table created:', results);
- }
- });
-
- pool.query(createExcludesTable, (err, results) => {
- if (err) {
- console.error('Error creating excludes table:', err);
- } else {
- console.log('Excludes table created:', results);
- }
- });
-
- pool.query(createGuildsTable, (err, results) => {
- if (err) {
- console.error('Error creating guilds info table:', err);
- } else {
- console.log('Guilds info table created:', results);
- }
- });
-}
-console.log('Initializing info tables...');
-await initInfoTables();
-console.log('Info tables initialized');
-
-// Ensure the table for a specific guild exists
-async function ensureGuildTableExists(guild, callback) {
- const createTableQuery = `
- CREATE TABLE IF NOT EXISTS \`${guild}\` (
- user_id VARCHAR(255) NOT NULL,
- xp INT DEFAULT 0,
- user_pfp TINYTEXT,
- user_name TINYTEXT,
- user_nickname TINYTEXT,
- user_level INT DEFAULT 0,
- user_xp_needed_next_level INT,
- user_progress_next_level DECIMAL(6, 2),
- PRIMARY KEY (user_id)
- )
- `;
- pool.query(createTableQuery, (err, results) => {
- if (err) {
- console.error(`Error creating table for guild ${guild}:`, err);
- callback(err);
- }
- else {
- console.log(`Table for guild ${guild} ensured:`, results);
- callback(null);
- }
- });
-}
-
-async function updateGuildInfo(guild, name, icon, members, callback) {
- const insertOrUpdateQuery = `
- INSERT INTO info_guilds (guild_id, guild_name, guild_icon, guild_members)
- VALUES (?, ?, ?, ?)
- ON DUPLICATE KEY UPDATE
- guild_name = VALUES(guild_name),
- guild_icon = VALUES(guild_icon),
- guild_members = VALUES(guild_members)
- `;
- pool.query(insertOrUpdateQuery, [guild, name, icon, members], (err, results) => {
- if (err) {
- console.error('Error updating guild info:', err);
- callback(err, null);
- }
- else {
- console.log('Guild info updated:', results);
- callback(null, results);
- }
- });
+app.use(express.static(path.join(__dirname, "public")));
+app.set("view engine", "ejs");
+app.set("views", path.join(__dirname, "views"));
+
+console.log("Initializing tables...");
+await initTables();
+console.log("Tables initialized");
+
+function authMiddleware(req: Request, res: Response, next: NextFunction) {
+ if (!req.headers.authorization || req.headers.authorization !== process.env.AUTH) {
+ return res
+ .status(403)
+ .json({ message: "Access denied" });
+ }
+ next();
}
-app.post('/post/:guild/', async (req, res) => {
+app.post("/post/:guild", authMiddleware, async (req, res) => {
const { guild } = req.params;
- const { name, icon, members, auth } = req.body;
+ const { name, icon, members } = req.body;
+
+ const [err, results] = await updateGuild({
+ id: guild,
+ name,
+ icon,
+ members,
+ updates_enabled: false,
+ updates_channel: "",
+ });
- if (auth !== process.env.AUTH) {
- return res.status(403).json({ message: 'Access denied. Auth token is missing' });
+ if (err) {
+ res.status(500).json({ message: "Internal server error" });
+ } else {
+ res.status(200).json(results);
}
-
- updateGuildInfo(guild, name, icon, members, (err, results) => {
- if (err) {
- res.status(500).json({ message: 'Internal server error' });
- } else {
- res.status(200).json(results);
- }
- });
});
-app.post('/post/:guild/:user/:auth', (req, res) => {
- const { guild, user, auth } = req.params;
+app.post("/post/:guild/:user", authMiddleware, async (req, res) => {
+ const { guild, user } = req.params;
const { name, pfp, xp, nickname } = req.body;
console.log(req.body);
const xpValue = parseInt(xp);
- if (auth !== process.env.AUTH) {
- return res.status(403).json({ message: 'Access denied. Auth token is missing' });
- }
+ const [err, result] = await getUser(user, guild);
- ensureGuildTableExists(guild, (err) => {
- if (err) {
- return res.status(500).json({ message: 'Internal server error' });
- }
+ if (err) {
+ console.error("Error fetching XP:", err);
+ return res.status(500).json({ message: "Internal server error" });
+ }
- const getXpQuery = `SELECT xp, user_level FROM \`${guild}\` WHERE user_id = ?`;
+ const currentXp = result?.xp ?? 0;
+ const currentLevelSaved = result?.level ?? 0;
+ const newXp = currentXp + xpValue;
+
+ const currentLevel = Math.floor(Math.sqrt(newXp / 100));
+ const nextLevel = currentLevel + 1;
+ const nextLevelXp = Math.pow(nextLevel, 2) * 100;
+ const xpNeededForNextLevel = nextLevelXp - newXp;
+ const currentLevelXp = Math.pow(currentLevel, 2) * 100;
+ const progressToNextLevel =
+ ((newXp - currentLevelXp) / (nextLevelXp - currentLevelXp)) * 100;
+
+ const updateQuery = `
+ INSERT INTO users
+ (id, guild_id, xp, pfp, name, nickname, level, xp_needed_next_level, progress_next_level)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ON DUPLICATE KEY UPDATE
+ xp = VALUES(xp),
+ pfp = VALUES(pfp),
+ name = VALUES(name),
+ nickname = VALUES(nickname),
+ level = VALUES(level),
+ xp_needed_next_level = VALUES(xp_needed_next_level),
+ progress_next_level = VALUES(progress_next_level)
+ `;
- pool.query(getXpQuery, [user], (err, results) => {
+ pool.query(
+ updateQuery,
+ [
+ user,
+ guild,
+ newXp,
+ pfp,
+ name,
+ nickname,
+ currentLevel,
+ xpNeededForNextLevel,
+ progressToNextLevel.toFixed(2),
+ ],
+ (err) => {
if (err) {
- console.error('Error fetching XP:', err);
- return res.status(500).json({ message: 'Internal server error' });
+ console.error("Error updating XP:", err);
+ return res
+ .status(500)
+ .json({ success: false, message: "Internal server error" });
+ } else {
+ res
+ .status(200)
+ .json({
+ success: true,
+ sendUpdateEvent: currentLevelSaved !== currentLevel,
+ level: currentLevel,
+ });
}
-
- const currentXp = results.length ? results[0].xp : 0;
- const currentLevelSaved = results.length ? results[0].user_level : 0;
- const newXp = currentXp + xpValue;
-
- const currentLevel = Math.floor(Math.sqrt(newXp / 100));
- const nextLevel = currentLevel + 1;
- const nextLevelXp = Math.pow(nextLevel, 2) * 100;
- const xpNeededForNextLevel = nextLevelXp - newXp;
- const currentLevelXp = Math.pow(currentLevel, 2) * 100;
- const progressToNextLevel = ((newXp - currentLevelXp) / (nextLevelXp - currentLevelXp)) * 100;
-
- const updateQuery = `
- INSERT INTO \`${guild}\` (user_id, xp, user_pfp, user_name, user_nickname, user_level, user_xp_needed_next_level, user_progress_next_level)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
- ON DUPLICATE KEY UPDATE
- xp = VALUES(xp),
- user_pfp = VALUES(user_pfp),
- user_name = VALUES(user_name),
- user_nickname = VALUES(user_nickname),
- user_level = VALUES(user_level),
- user_xp_needed_next_level = VALUES(user_xp_needed_next_level),
- user_progress_next_level = VALUES(user_progress_next_level)
- `;
-
- pool.query(updateQuery, [user, newXp, pfp, name, nickname, currentLevel, xpNeededForNextLevel, progressToNextLevel.toFixed(2)], (err, results) => {
- if (err) {
- console.error('Error updating XP:', err);
- return res.status(500).json({ success: false, message: 'Internal server error' });
- } else {
- res.status(200).json({ success: true, sendUpdateEvent: currentLevelSaved !== currentLevel, level: currentLevel});
- }
- });
- });
- });
+ },
+ );
});
-app.get('/get/:guild/:user', (req, res) => {
+app.get("/get/:guild/:user", async (req, res) => {
const { guild, user } = req.params;
- const selectQuery = `
- SELECT * FROM \`${guild}\` WHERE user_id = ?
- `;
- pool.query(selectQuery, [user], (err, results) => {
- if (err) {
- console.error('Error fetching XP:', err);
- res.status(500).json({ message: 'Internal server error' });
- }
- else if (results.length > 0) {
- res.status(200).json(results[0]);
- }
- else {
- res.status(404).json({ message: 'User not found' });
- }
- });
+ const [err, result] = await getUser(user, guild);
+
+ if (err) {
+ console.error("Error fetching user:", err);
+ res.status(500).json({ message: "Internal server error" });
+ } else if (result) {
+ res.status(200).json(result);
+ } else {
+ res.status(404).json({ message: "User not found" });
+ }
});
-app.get('/get/:guild', async (req, res) => {
+app.get("/get/:guild", async (req, res) => {
const { guild } = req.params;
- const returnData = { "guild": {}, "leaderboard": [] };
-
- const selectQuery = `
- SELECT * FROM \`${guild}\` ORDER BY xp DESC;
- `;
- const selectQuery2 = `
- SELECT * FROM info_guilds WHERE guild_id = ${guild};
- `;
-
- try {
- const results1 = await new Promise((resolve, reject) => {
- pool.query(selectQuery, (err, results) => {
- if (err) {
- console.error('Error fetching XP:', err);
- reject(err);
- } else {
- resolve(results);
- }
- });
- });
- const results2 = await new Promise((resolve, reject) => {
- pool.query(selectQuery2, (err, results) => {
- if (err) {
- console.error('Error fetching XP:', err);
- reject(err);
- } else {
- resolve(results);
- }
- });
+ const [guildErr, guildData] = await getGuild(guild);
+ const [usersErr, usersData] = await getUsers(guild);
+
+ if (guildErr) {
+ console.error("Error fetching guild:", guildErr);
+ res.status(500).json({ message: "Internal server error" });
+ } else if (usersErr) {
+ console.error("Error fetching users:", usersErr);
+ res.status(500).json({ message: "Internal server error" });
+ } else if (!guildData) {
+ res.status(404).json({ message: "Guild not found" });
+ } else {
+ res.status(200).json({
+ guild: guildData,
+ leaderboard: usersData,
});
-
- returnData.leaderboard = results1;
- returnData.guild = results2[0];
-
- return res.status(200).json(returnData);
- } catch (error) {
- console.error('Error fetching XP:', error);
- return res.status(500).json({ message: 'Internal server error' });
}
});
-app.post('/admin/:action/:guild/:target', async (req, res) => {
+app.post("/admin/:action/:guild/:target", authMiddleware, async (req, res) => {
const { guild, action, target } = req.params;
- const { auth, extraData } = req.body;
-
- if (auth !== process.env.AUTH) {
- return res.status(403).json({ message: 'Access denied. Auth token is missing' });
- }
-
- let apiSuccess;
+ const { extraData } = req.body;
switch (action) {
- case 'include':
+ case "include":
// target: channel id
// run function to include target to guild
break;
- case 'exclude':
+ case "exclude":
// target: channel id
// run function to exclude target from guild
break;
- case 'updates':
- if (target !== 'enable' && target !== 'disable' && target !== 'get') {
- return res.status(400).json({ message: 'Illegal request' });
+ case "updates":
+ if (target !== "enable" && target !== "disable" && target !== "get") {
+ return res.status(400).json({ message: "Illegal request" });
}
switch (target) {
- case 'enable':
+ case "enable":
if (!extraData || !extraData.channelId) {
- return res.status(400).json({ message: 'Illegal request' });
+ return res.status(400).json({ message: "Illegal request" });
}
try {
const data = await adminUpdatesAdd(guild, extraData.channelId);
return res.status(200).json(data);
} catch (error) {
- return res.status(500).json({ message: 'Internal server error' });
+ return res.status(500).json({ message: "Internal server error" });
}
- case 'disable':
+ case "disable":
try {
const data = await adminUpdatesRemove(guild);
return res.status(200).json(data);
} catch (error) {
- return res.status(500).json({ message: 'Internal server error' });
+ return res.status(500).json({ message: "Internal server error" });
}
default:
try {
const data = await adminUpdatesGet(guild);
return res.status(200).json(data);
} catch (error) {
- return res.status(500).json({ message: 'Internal server error' });
+ return res.status(500).json({ message: "Internal server error" });
}
}
- case 'roles':
- if (target !== 'add' && target !== 'remove' && target !== 'get') {
- return res.status(400).json({ message: 'Illegal request' });
+ case "roles":
+ if (target !== "add" && target !== "remove" && target !== "get") {
+ return res.status(400).json({ message: "Illegal request" });
}
- if ((target === 'add' || target === 'remove') && !extraData) {
- return res.status(400).json({ message: 'Illegal request' });
+ if ((target === "add" || target === "remove") && !extraData) {
+ return res.status(400).json({ message: "Illegal request" });
}
switch (target) {
- case 'get':
+ case "get":
try {
const data = await adminRolesGet(guild);
return res.status(200).json(data);
} catch (error) {
- return res.status(500).json({ message: 'Internal server error' });
+ return res.status(500).json({ message: "Internal server error" });
}
- case 'remove':
+ case "remove":
try {
const data = await adminRolesRemove(guild, extraData.role);
return res.status(200).json(data);
} catch (error) {
- return res.status(500).json({ message: 'Internal server error' });
+ return res.status(500).json({ message: "Internal server error" });
}
- case 'add':
+ case "add":
try {
- const data = await adminRolesAdd(guild, extraData.role, extraData.level);
+ const data = await adminRolesAdd(
+ guild,
+ extraData.role,
+ extraData.level,
+ );
return res.status(200).json(data);
} catch (error) {
- return res.status(500).json({ message: 'Internal server error' });
+ return res.status(500).json({ message: "Internal server error" });
}
default:
- return res.status(500).json({ message: 'Internal server error' });
+ return res.status(500).json({ message: "Internal server error" });
}
default:
- return res.status(400).json({ message: 'Illegal request' });
+ return res.status(400).json({ message: "Illegal request" });
}
});
-app.get('/leaderboard/:guild', async (req, res) => {
+app.get("/leaderboard/:guild", async (req, res) => {
const { guild } = req.params;
- const response = await fetch(`http://localhost:18103/get/${guild}/`);
- if (!response.ok) {
- return res.status(404).json({ message: 'No guild was found with this ID' });
+ const [guildErr, guildData] = await getGuild(guild);
+ const [usersErr, usersData] = await getUsers(guild);
+
+ if (guildErr) {
+ console.error("Error fetching guild:", guildErr);
+ res.status(500).json({ message: "Internal server error" });
+ } else if (usersErr) {
+ console.error("Error fetching users:", usersErr);
+ res.status(500).json({ message: "Internal server error" });
}
- const data = await response.json();
- res.render('leaderboard', { guild: data.guild, leaderboard: data.leaderboard });
-});
-
-async function getBotInfo() {
- const selectGuildsCountQuery = `
- SELECT COUNT(*) AS total_guilds FROM info_guilds;
- `;
-
- const selectTotalMembersQuery = `
- SELECT SUM(guild_members) AS total_members FROM info_guilds;
- `;
-
- try {
- const guildsCountResult = await new Promise((resolve, reject) => {
- pool.query(selectGuildsCountQuery, (err, results) => {
- if (err) {
- console.error('Error fetching guilds count:', err);
- reject(err);
- } else {
- resolve(results[0].total_guilds);
- }
- });
- });
- const totalMembersResult = await new Promise((resolve, reject) => {
- pool.query(selectTotalMembersQuery, (err, results) => {
- if (err) {
- console.error('Error fetching total members:', err);
- reject(err);
- } else {
- resolve(results[0].total_members);
- }
- });
- });
-
- const botInfo = {
- total_guilds: guildsCountResult,
- total_members: totalMembersResult,
- };
-
- return botInfo
- } catch (error) {
- console.error('Error fetching bot info:', error);
- return null
- }
-}
+ res.render("leaderboard", {
+ guild: guildData,
+ leaderboard: usersData,
+ });
+});
-app.get('/', async (req, res) => {
- const botInfo = await getBotInfo();
- res.render('index', { botInfo: botInfo });
+app.get("/", async (_req, res) => {
+ // TODO: handle error
+ const [err, botInfo] = await getBotInfo();
+ res.render("index", { botInfo });
});
-app.get('/invite', (req, res) => {
- res.status(308).redirect('https://discord.com/oauth2/authorize?client_id=1245807579624378601&permissions=1099780115520&integration_type=0&scope=bot+applications.commands')
-})
+app.get("/invite", (_req, res) =>
+ res
+ .status(308)
+ .redirect(
+ "https://discord.com/oauth2/authorize?client_id=1245807579624378601&permissions=1099780115520&integration_type=0&scope=bot+applications.commands",
+ )
+);
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
+// TODO: actually implement this in a real way
//#region Admin: Roles
async function adminRolesGet(guild: string) {
- const selectRolesQuery = `SELECT role_id, level FROM info_roles WHERE guild_id = ?`;
+ const selectRolesQuery = `SELECT id, level FROM roles WHERE guild_id = ?`;
return new Promise((resolve, reject) => {
pool.query(selectRolesQuery, [guild], (err, results) => {
if (err) {
- console.error('Error fetching roles:', err);
+ console.error("Error fetching roles:", err);
reject(err);
} else {
resolve(results);
@@ -454,14 +296,14 @@ async function adminRolesGet(guild: string) {
async function adminRolesRemove(guild: string, role: string) {
const deleteRoleQuery = `
- DELETE FROM info_roles
- WHERE guild_id = ? AND role_id = ?
+ DELETE FROM roles
+ WHERE id = ? AND guild_id = ?
`;
return new Promise((resolve, reject) => {
- pool.query(deleteRoleQuery, [guild, role], (err, results) => {
+ pool.query(deleteRoleQuery, [role, guild], (err, results) => {
if (err) {
- console.error('Error removing role:', err);
+ console.error("Error removing role:", err);
reject(err);
} else {
resolve(results);
@@ -472,14 +314,14 @@ async function adminRolesRemove(guild: string, role: string) {
async function adminRolesAdd(guild: string, role: string, level: number) {
const insertRoleQuery = `
- INSERT INTO info_roles (guild_id, role_id, level)
+ INSERT INTO roles (id, guild_id, level)
VALUES (?, ?, ?)
`;
return new Promise((resolve, reject) => {
- pool.query(insertRoleQuery, [guild, role, level], (err, results) => {
+ pool.query(insertRoleQuery, [role, guild, level], (err, results) => {
if (err) {
- console.error('Error adding role:', err);
+ console.error("Error adding role:", err);
reject(err);
} else {
resolve(results);
@@ -489,14 +331,15 @@ async function adminRolesAdd(guild: string, role: string, level: number) {
}
//#endregion
+// TODO: actually implement this in a real way
//#region Admin: Updates
async function adminUpdatesGet(guildId: string) {
- const selectUpdatesQuery = `SELECT * FROM info_updates WHERE guild_id = ?`;
+ const selectUpdatesQuery = `SELECT * FROM updates WHERE guild_id = ?`;
return new Promise((resolve, reject) => {
pool.query(selectUpdatesQuery, [guildId], (err, results) => {
if (err) {
- console.error('Error fetching updates:', err);
+ console.error("Error fetching updates:", err);
reject(err);
} else {
resolve(results);
@@ -507,35 +350,39 @@ async function adminUpdatesGet(guildId: string) {
async function adminUpdatesAdd(guildId: string, channelId: string) {
const insertUpdatesQuery = `
- INSERT INTO info_updates (guild_id, enabled, channel_id)
- VALUES (?, TRUE, ?)
+ INSERT INTO updates (guild_id, channel_id, enabled)
+ VALUES (?, ?, TRUE)
ON DUPLICATE KEY UPDATE
- enabled = TRUE,
- channel_id = ?
+ enabled = TRUE,
+ channel_id = VALUES(channel_id)
`;
return new Promise((resolve, reject) => {
- pool.query(insertUpdatesQuery, [guildId, channelId, channelId], (err, results) => {
- if (err) {
- console.error('Error enabling updates:', err);
- reject(err);
- } else {
- resolve(results);
- }
- });
+ pool.query(
+ insertUpdatesQuery,
+ [guildId, channelId],
+ (err, results) => {
+ if (err) {
+ console.error("Error enabling updates:", err);
+ reject(err);
+ } else {
+ resolve(results);
+ }
+ },
+ );
});
}
async function adminUpdatesRemove(guildId: string) {
const deleteUpdatesQuery = `
- DELETE FROM info_updates
+ DELETE FROM updates
WHERE guild_id = ?
`;
return new Promise((resolve, reject) => {
pool.query(deleteUpdatesQuery, [guildId], (err, results) => {
if (err) {
- console.error('Error disabling updates:', err);
+ console.error("Error disabling updates:", err);
reject(err);
} else {
resolve(results);
@@ -544,4 +391,4 @@ async function adminUpdatesRemove(guildId: string) {
});
}
-//#endregion
\ No newline at end of file
+//#endregion
diff --git a/api/views/leaderboard.ejs b/api/views/leaderboard.ejs
index 2b43b6a..c935a14 100644
--- a/api/views/leaderboard.ejs
+++ b/api/views/leaderboard.ejs
@@ -4,7 +4,7 @@
- Leaderboard for <%= guild.guild_name %>
+ Leaderboard for <%= guild.name %>
@@ -14,9 +14,9 @@
-

+
- <%= guild.guild_name %>
+ <%= guild.name %>
@@ -25,14 +25,14 @@
#<%= index + 1 %>
-

+
-
- <%= user.user_nickname %>
+
+ <%= user.nickname %>
XP: <%= user.xp.toLocaleString() %>
-
Level <%= user.user_level.toLocaleString() %> | <%= user.xp.toLocaleString() %>/<%= (user.xp + user.user_xp_needed_next_level).toLocaleString() %> points to next level (<%= user.user_progress_next_level %>%)
+
Level <%= user.level.toLocaleString() %> | <%= user.xp.toLocaleString() %>/<%= (user.xp + user.xp_needed_next_level).toLocaleString() %> points to next level (<%= user.progress_next_level %>%)
diff --git a/bot/utils/requestAPI.ts b/bot/utils/requestAPI.ts
index 5b2fa91..d4bb543 100644
--- a/bot/utils/requestAPI.ts
+++ b/bot/utils/requestAPI.ts
@@ -1,9 +1,10 @@
import handleLevelChange from "./handleLevelChange";
export async function makePOSTRequest(guild: string, user: string, xp: number, pfp: string, name: string, nickname: string) {
- await fetch(`http://localhost:18103/post/${guild}/${user}/${process.env.AUTH}`, {
+ await fetch(`http://localhost:18103/post/${guild}/${user}`, {
headers: {
'Content-Type': 'application/json',
+ 'Authorization': process.env.AUTH as string,
},
method: 'POST',
body: JSON.stringify({ xp, pfp, name, nickname }),
@@ -42,9 +43,10 @@ export async function updateGuildInfo(guild: string, name: string, icon: string,
await fetch(`http://localhost:18103/post/${guild}`, {
headers: {
'Content-Type': 'application/json',
+ 'Authorization': process.env.AUTH as string,
},
method: 'POST',
- body: JSON.stringify({ name, icon, members, auth: process.env.AUTH }),
+ body: JSON.stringify({ name, icon, members }),
}).then(res => {
return res.json()
}).then(data => {
@@ -57,11 +59,10 @@ export async function getRoles(guild: string) {
const response = await fetch(`http://localhost:18103/admin/roles/${guild}/get`, {
headers: {
'Content-Type': 'application/json',
+ 'Authorization': process.env.AUTH as string,
},
+ body: JSON.stringify({}),
referrerPolicy: 'strict-origin-when-cross-origin',
- body: JSON.stringify({
- auth: process.env.AUTH,
- }),
method: 'POST',
});
@@ -74,9 +75,9 @@ export async function removeRole(guild: string, role: string): Promise
const response = await fetch(`http://localhost:18103/admin/roles/${guild}/remove`, {
"headers": {
'Content-Type': 'application/json',
+ 'Authorization': process.env.AUTH as string,
},
"body": JSON.stringify({
- auth: process.env.AUTH,
extraData: {
role: role,
}
@@ -90,9 +91,9 @@ export async function addRole(guild: string, role: string, level: number): Promi
const response = await fetch(`http://localhost:18103/admin/roles/${guild}/add`, {
"headers": {
'Content-Type': 'application/json',
+ 'Authorization': process.env.AUTH as string,
},
"body": JSON.stringify({
- auth: process.env.AUTH,
extraData: {
role: role,
level: level
@@ -111,26 +112,35 @@ export async function addRole(guild: string, role: string, level: number): Promi
//#region Updates
export async function checkIfGuildHasUpdatesEnabled(guild: string) {
const response = await fetch(`http://localhost:18103/admin/updates/${guild}/get`, {
- "headers": { 'Content-Type': 'application/json' },
- "body": JSON.stringify({ auth: process.env.AUTH }),
+ "headers": {
+ 'Content-Type': 'application/json',
+ 'Authorization': process.env.AUTH as string
+ },
+ "body": JSON.stringify({}),
"method": "POST"
});
return response.status === 200;
}
export async function enableUpdates(guild: string, channelId: string) {
const response = await fetch(`http://localhost:18103/admin/updates/${guild}/enable`, {
- "headers": { 'Content-Type': 'application/json' },
- "body": JSON.stringify({ auth: process.env.AUTH, extraData: { channelId } }),
+ "headers": {
+ 'Content-Type': 'application/json',
+ 'Authorization': process.env.AUTH as string,
+ },
+ "body": JSON.stringify({ extraData: { channelId } }),
"method": "POST"
});
return response.status === 200;
}
export async function disableUpdates(guild: string) {
const response = await fetch(`http://localhost:18103/admin/updates/${guild}/disable`, {
- "headers": { 'Content-Type': 'application/json' },
- "body": JSON.stringify({ auth: process.env.AUTH }),
+ "headers": {
+ 'Content-Type': 'application/json',
+ 'Authorization': process.env.AUTH as string,
+ },
+ "body": JSON.stringify({}),
"method": "POST"
});
return response.status === 200;
}
-//#endregion
\ No newline at end of file
+//#endregion