Skip to content

Commit 68cbc30

Browse files
committed
feat: added member remove event
1 parent c705d81 commit 68cbc30

File tree

14 files changed

+3957
-5763
lines changed

14 files changed

+3957
-5763
lines changed

.eslintrc.json

Lines changed: 0 additions & 115 deletions
This file was deleted.

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ bun run dev:bot
3939
```
4040

4141
# Changelog
42+
## Stable 1.0
43+
* A new, redesigned site using NextJS
44+
* Users that are no longer in your server will be hidden from the public leaderboard
45+
4246
## Beta 0.1
4347
Thanks to @ToastedDev for his contributions to the bot. Here are some changes that were made
4448
* General formatting fixes (#8)
@@ -52,11 +56,14 @@ Thanks to @ToastedDev for his contributions to the bot. Here are some changes th
5256
* Fixed wrong data being shown on the leaderboard
5357

5458
# Roadmap
55-
* Rewritten site using NextJS
59+
Anything crossed out means that it's been done on the dev branch, but not pushed out to production
60+
* ~~Rewritten site using NextJS~~
5661
* Auto-updating cached user information
5762
* Better privacy controls
58-
* Live updates
63+
* ~~Live updates~~
5964
* Track guilds and users xp
65+
* Live updates (FIX)
66+
* Hourly/daily updates etc in a chosen channel
6067

6168

6269
Want to add more features? Join our server (linked above) and add a post to `feature-requests`

api/src/db/init.ts

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { pool } from ".";
22

33
export async function initTables() {
4-
const createGuildsTable = `
4+
const createGuildsTable = `
55
CREATE TABLE IF NOT EXISTS guilds (
66
id VARCHAR(255) NOT NULL PRIMARY KEY,
77
name VARCHAR(255),
@@ -13,7 +13,7 @@ export async function initTables() {
1313
is_in_guild BOOLEAN DEFAULT TRUE
1414
)
1515
`;
16-
const createUsersTable = `
16+
const createUsersTable = `
1717
CREATE TABLE IF NOT EXISTS users (
1818
id VARCHAR(255) NOT NULL,
1919
guild_id VARCHAR(255) NOT NULL,
@@ -24,41 +24,40 @@ export async function initTables() {
2424
level INT DEFAULT 0,
2525
xp_needed_next_level INT,
2626
progress_next_level DECIMAL(6, 2),
27+
user_is_in_guild BOOLEAN DEFAULT TRUE,
2728
PRIMARY KEY (id, guild_id)
2829
)
2930
`;
30-
// FOREIGN KEY (guild_id) REFERENCES guilds(id)
31-
const createRolesTable = `
31+
const createRolesTable = `
3232
CREATE TABLE IF NOT EXISTS roles (
3333
id VARCHAR(255) NOT NULL PRIMARY KEY,
3434
guild_id VARCHAR(255) NOT NULL,
3535
name VARCHAR(255),
3636
level INT NOT NULL
3737
)
3838
`;
39-
// FOREIGN KEY (guild_id) REFERENCES guilds(id)
4039

41-
pool.query(createGuildsTable, (err) => {
42-
if (err) {
43-
console.error("Error creating guilds table:", err);
44-
} else {
45-
console.log("Guilds table created");
46-
}
47-
});
40+
pool.query(createGuildsTable, (err) => {
41+
if (err) {
42+
console.error("Error creating guilds table:", err);
43+
} else {
44+
console.log("Guilds table created");
45+
}
46+
});
4847

49-
pool.query(createUsersTable, (err) => {
50-
if (err) {
51-
console.error("Error creating users table:", err);
52-
} else {
53-
console.log("Users table created");
54-
}
55-
});
48+
pool.query(createUsersTable, (err) => {
49+
if (err) {
50+
console.error("Error creating users table:", err);
51+
} else {
52+
console.log("Users table created");
53+
}
54+
});
5655

57-
pool.query(createRolesTable, (err) => {
58-
if (err) {
59-
console.error("Error creating roles table:", err);
60-
} else {
61-
console.log("Roles table created");
62-
}
63-
});
56+
pool.query(createRolesTable, (err) => {
57+
if (err) {
58+
console.error("Error creating roles table:", err);
59+
} else {
60+
console.log("Roles table created");
61+
}
62+
});
6463
}

api/src/db/queries/users.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface User {
1515

1616
export async function getUsers(guildId: string): Promise<[QueryError, null] | [null, User[]]> {
1717
return new Promise((resolve, reject) => {
18-
pool.query("SELECT * FROM users WHERE guild_id = ? ORDER BY xp DESC", [guildId], (err, results) => {
18+
pool.query("SELECT * FROM users WHERE guild_id = ? AND user_is_in_guild = ? ORDER BY xp DESC", [guildId, true], (err, results) => {
1919
if (err) {
2020
reject([err, null]);
2121
} else {
@@ -37,6 +37,19 @@ export async function getUser(userId: string, guildId: string): Promise<[QueryEr
3737
});
3838
}
3939

40+
export async function removeUser(userId: string, guildId: string): Promise<[QueryError | null, boolean]> {
41+
return new Promise((resolve, reject) => {
42+
pool.query("UPDATE users SET user_is_in_guild = ? WHERE id = ? AND guild_id = ?", [false, userId, guildId], (err) => {
43+
if (err) {
44+
reject([err, false]);
45+
} else {
46+
resolve([null, true]);
47+
}
48+
});
49+
});
50+
51+
}
52+
4053
export async function setXP(guildId: string, userId: string, xp: number): Promise<[QueryError | null, boolean]> {
4154
const newLevel = Math.floor(Math.sqrt(xp / 100));
4255
const nextLevel = newLevel + 1;
@@ -47,7 +60,7 @@ export async function setXP(guildId: string, userId: string, xp: number): Promis
4760
((xp - currentLevelXp) / (nextLevelXp - currentLevelXp)) * 100;
4861

4962
return new Promise((resolve, reject) => {
50-
pool.query("UPDATE users SET xp = ?, level = ?, xp_needed_next_level = ?, progress_next_level = ? WHERE id = ? AND guild_id = ?", [xp, newLevel, xpNeededForNextLevel.toFixed(2), progressToNextLevel.toFixed(2), userId, guildId], (err) => {
63+
pool.query("UPDATE users SET xp = ?, level = ?, xp_needed_next_level = ?, progress_next_level = ?, user_is_in_guild = ? WHERE id = ? AND guild_id = ?", [xp, newLevel, xpNeededForNextLevel.toFixed(2), progressToNextLevel.toFixed(2), true, userId, guildId], (err) => {
5164
if (err) {
5265
reject([err, false]);
5366
} else {

api/src/index.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import express, { type NextFunction, type Request, type Response } from "express";
22
import cors from "cors";
33
import path from "path";
4-
import { getBotInfo, getGuild, getUser, getUsers, initTables, pool, updateGuild, enableUpdates, disableUpdates, setCooldown, setUpdatesChannel, setXP, setLevel, removeGuild } from "./db";
4+
import { getBotInfo, getGuild, getUser, getUsers, initTables, pool, updateGuild, enableUpdates, disableUpdates, setCooldown, setUpdatesChannel, setXP, setLevel, removeGuild, removeUser } from "./db";
55

66
const app = express();
77
const PORT = 18103;
@@ -56,6 +56,17 @@ app.post('/post/:guild/remove', authMiddleware, async (req, res) => {
5656
}
5757
})
5858

59+
app.post('/post/:guild/:user/remove', authMiddleware, async (req, res) => {
60+
const { guild, user } = req.params;
61+
const [err, results] = await removeUser(user, guild);
62+
63+
if (err) {
64+
res.status(500).json({ message: "Internal server error" });
65+
} else {
66+
res.status(200).json(results);
67+
}
68+
})
69+
5970
app.post("/post/:guild/:user", authMiddleware, async (req, res) => {
6071
const { guild, user } = req.params;
6172
const { name, pfp, xp, nickname } = req.body;
@@ -128,6 +139,15 @@ app.post("/post/:guild/:user", authMiddleware, async (req, res) => {
128139
);
129140
});
130141

142+
app.get('/get/botinfo', async (_req, res) => {
143+
const [err, data] = await getBotInfo();
144+
if (err) {
145+
console.error("Error fetching bot info:", err);
146+
return res.status(500).json({ message: "Internal server error" });
147+
}
148+
return res.status(200).json(data);
149+
});
150+
131151
app.get("/get/:guild/:user", async (req, res) => {
132152
const { guild, user } = req.params;
133153

bot/src/events/memberRemove.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Events } from "discord.js";
2+
import client from "../index";
3+
import { removeUser } from "../utils/requestAPI";
4+
5+
client.on(Events.GuildMemberRemove, async (member) => {
6+
try {
7+
const success = await removeUser(member.id, member.guild.id);
8+
if (success) {
9+
console.log(`Removed user ${member.user.username} from the database`);
10+
} else {
11+
console.error(`Failed to remove user ${member.user.username} from the database`);
12+
}
13+
} catch (e) {
14+
console.error(e);
15+
}
16+
})

bot/src/utils/requestAPI.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ export async function removeGuild(guild: string) {
6464
})
6565
}
6666

67+
export async function removeUser(guild: string, user: string) {
68+
const response = await fetch(`http://localhost:18103/post/${guild}/${user}/remove`, {
69+
headers: {
70+
'Content-Type': 'application/json',
71+
'Authorization': process.env.AUTH as string,
72+
},
73+
method: 'POST',
74+
})
75+
return response.status === 200;
76+
}
77+
6778
export async function setXP(guild: string, user: string, xp: number) {
6879
const response = await fetch(`http://localhost:18103/admin/set/${guild}/xp`, {
6980
"headers": {

eslint.config.mjs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@ import tseslint from "typescript-eslint";
66
import nextjsConfig from "eslint-config-neon/flat/next.js";
77

88
export default tseslint.config(
9-
{
10-
ignores: ["web/.next"],
11-
},
12-
eslint.configs.recommended,
13-
...tseslint.configs.recommended,
14-
...tseslint.configs.stylistic,
15-
{
16-
files: ["apps/web/**/*.{ts,tsx,js,jsx}"],
17-
...nextjsConfig[0],
18-
rules: {
19-
...nextjsConfig[0].rules,
20-
"@next/next/no-duplicate-head": 0,
21-
},
22-
},
9+
{
10+
ignores: ["web/.next"],
11+
},
12+
eslint.configs.recommended,
13+
...tseslint.configs.recommended,
14+
...tseslint.configs.stylistic,
15+
{
16+
files: ["apps/web/**/*.{ts,tsx,js,jsx}"],
17+
...nextjsConfig[0],
18+
rules: {
19+
...nextjsConfig[0].rules,
20+
"@next/next/no-duplicate-head": 0,
21+
},
22+
},
2323
);

0 commit comments

Comments
 (0)