Skip to content

Commit c7c5376

Browse files
committed
feat(updates): refactor
1 parent 03d759d commit c7c5376

File tree

8 files changed

+145
-95
lines changed

8 files changed

+145
-95
lines changed

api/db/init.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ export async function initTables() {
77
name VARCHAR(255),
88
icon VARCHAR(255),
99
members INT,
10-
cooldown INT DEFAULT 30000
10+
cooldown INT DEFAULT 30000,
11+
updates_enabled BOOLEAN DEFAULT FALSE,
12+
updates_channel_id VARCHAR(255) DEFAULT NULL
1113
)
1214
`;
1315
const createUsersTable = `
@@ -34,14 +36,6 @@ export async function initTables() {
3436
)
3537
`;
3638
// FOREIGN KEY (guild_id) REFERENCES guilds(id)
37-
const createUpdatesTable = `
38-
CREATE TABLE IF NOT EXISTS updates (
39-
guild_id VARCHAR(255) NOT NULL PRIMARY KEY,
40-
channel_id VARCHAR(255) NOT NULL,
41-
enabled BOOLEAN DEFAULT FALSE
42-
)
43-
`;
44-
// FOREIGN KEY (guild_id) REFERENCES guilds(id)
4539

4640
pool.query(createGuildsTable, (err) => {
4741
if (err) {
@@ -66,12 +60,4 @@ export async function initTables() {
6660
console.log("Roles table created");
6761
}
6862
});
69-
70-
pool.query(createUpdatesTable, (err) => {
71-
if (err) {
72-
console.error("Error creating updates table:", err);
73-
} else {
74-
console.log("Updates table created");
75-
}
76-
});
7763
}

api/db/queries/guilds.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ export interface Guild {
77
icon: string;
88
members: number;
99
cooldown: number;
10+
updates_enabled: 0 | 1;
11+
updates_channel_id: string | null;
1012
}
1113

14+
1215
export async function getGuild(guildId: string): Promise<[QueryError, null] | [null, Guild | null]> {
1316
return new Promise((resolve, reject) => {
1417
pool.query("SELECT * FROM guilds WHERE id = ?", [guildId], (err, results) => {
@@ -21,24 +24,22 @@ export async function getGuild(guildId: string): Promise<[QueryError, null] | [n
2124
});
2225
}
2326

24-
export async function updateGuild(guild: Guild): Promise<[QueryError | null, null] | [null, Guild[]]> {
27+
export async function updateGuild(guild: Omit<Guild, "cooldown" | "updates_enabled" | "updates_channel_id">): Promise<[QueryError | null, null] | [null, Guild[]]> {
2528
return new Promise((resolve, reject) => {
2629
pool.query(
2730
`
28-
INSERT INTO guilds (id, name, icon, members, cooldown)
31+
INSERT INTO guilds (id, name, icon, members)
2932
VALUES (?, ?, ?, ?, ?, ?)
3033
ON DUPLICATE KEY UPDATE
3134
name = VALUES(name),
3235
icon = VALUES(icon),
33-
members = VALUES(members),
34-
cooldown = VALUES(cooldown)
36+
members = VALUES(members)
3537
`,
3638
[
3739
guild.id,
3840
guild.name,
3941
guild.icon,
4042
guild.members,
41-
guild.cooldown
4243
],
4344
(err, results) => {
4445
console.dir(results, { depth: null });

api/db/queries/updates.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,38 @@ export interface Updates {
77
enabled: boolean;
88
}
99

10-
export async function getUpdates(guildId: string): Promise<[QueryError | null, Updates[] | null]> {
10+
export async function enableUpdates(guildId: string): Promise<[QueryError | null, boolean]> {
1111
return new Promise((resolve, reject) => {
12-
pool.query("SELECT * FROM updates WHERE guild_id = ?", [guildId], (err, results) => {
13-
if (err) {
14-
reject([err, null]);
15-
} else {
16-
resolve([null, results as Updates[]]);
17-
}
18-
});
12+
pool.query(
13+
`
14+
UPDATE guilds SET updates_enabled = TRUE WHERE id = ?
15+
`,
16+
[
17+
guildId,
18+
],
19+
(err) => {
20+
if (err) {
21+
reject([err, false]);
22+
} else {
23+
resolve([null, true]);
24+
}
25+
},
26+
);
1927
});
2028
}
2129

22-
export async function enableUpdates(guildId: string, channelId: string): Promise<[QueryError | null, true | null]> {
30+
export async function disableUpdates(guildId: string): Promise<[QueryError | null, boolean]> {
2331
return new Promise((resolve, reject) => {
2432
pool.query(
2533
`
26-
INSERT INTO updates (guild_id, channel_id, enabled)
27-
VALUES (?, ?, ?)
28-
ON DUPLICATE KEY UPDATE
29-
channel_id = VALUES(channel_id),
30-
enabled = VALUES(enabled)
34+
UPDATE guilds SET updates_enabled = FALSE WHERE id = ?
3135
`,
3236
[
3337
guildId,
34-
channelId,
35-
true,
3638
],
3739
(err) => {
3840
if (err) {
39-
reject([err, null]);
41+
reject([err, false]);
4042
} else {
4143
resolve([null, true]);
4244
}
@@ -45,21 +47,19 @@ export async function enableUpdates(guildId: string, channelId: string): Promise
4547
});
4648
}
4749

48-
export async function disableUpdates(guildId: string): Promise<[QueryError | null, true | null]> {
50+
export async function setUpdatesChannel(guildId: string, channelId: string | null): Promise<[QueryError | null, boolean]> {
4951
return new Promise((resolve, reject) => {
5052
pool.query(
5153
`
52-
UPDATE updates
53-
SET enabled = ?
54-
WHERE guild_id = ?
54+
UPDATE guilds SET updates_channel_id = ? WHERE id = ?
5555
`,
5656
[
57-
false,
57+
channelId,
5858
guildId,
5959
],
6060
(err) => {
6161
if (err) {
62-
reject([err, null]);
62+
reject([err, false]);
6363
} else {
6464
resolve([null, true]);
6565
}

api/index.ts

Lines changed: 23 additions & 8 deletions
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, getUpdates, enableUpdates, disableUpdates, setCooldown } from "./db";
4+
import { getBotInfo, getGuild, getUser, getUsers, initTables, pool, updateGuild, enableUpdates, disableUpdates, setCooldown, setUpdatesChannel } from "./db";
55

66
const app = express();
77
const PORT = 18103;
@@ -34,7 +34,6 @@ app.post("/post/:guild", authMiddleware, async (req, res) => {
3434
name,
3535
icon,
3636
members,
37-
cooldown: 30_000,
3837
});
3938

4039
if (err) {
@@ -57,6 +56,7 @@ app.post("/post/:guild/:user", authMiddleware, async (req, res) => {
5756
return res.status(500).json({ message: "Internal server error" });
5857
}
5958

59+
6060
const currentXp = result?.xp ?? 0;
6161
const currentLevelSaved = result?.level ?? 0;
6262
const newXp = currentXp + xpValue;
@@ -168,15 +168,12 @@ app.post("/admin/:action/:guild/:target", authMiddleware, async (req, res) => {
168168
// run function to exclude target from guild
169169
break;
170170
case "updates":
171-
if (target !== "enable" && target !== "disable" && target !== "get") {
171+
if (target !== "enable" && target !== "disable" && target !== "set" && target !== "get") {
172172
return res.status(400).json({ message: "Illegal request" });
173173
}
174174

175175
switch (target) {
176176
case "enable":
177-
if (!extraData || !extraData.channelId) {
178-
return res.status(400).json({ message: "Illegal request" });
179-
}
180177
try {
181178
const [err, success] = await enableUpdates(guild, extraData.channelId);
182179
if (err) {
@@ -198,13 +195,31 @@ app.post("/admin/:action/:guild/:target", authMiddleware, async (req, res) => {
198195
} catch (err) {
199196
return res.status(500).json({ message: "Internal server error", err });
200197
}
198+
case 'set':
199+
if (!extraData || typeof extraData.channelId === "undefined") {
200+
return res.status(400).json({ message: "Illegal request" });
201+
}
202+
203+
try {
204+
const [err, success] = await setUpdatesChannel(guild, extraData.channelId);
205+
if (err) {
206+
return res.status(500).json({ message: 'Internal server error', err });
207+
} else {
208+
return res.status(200).json(success);
209+
}
210+
} catch (err) {
211+
return res.status(500).json({ message: 'Internal server error', err });
212+
}
201213
default:
202214
try {
203-
const [err, data] = await getUpdates(guild);
215+
const [err, data] = await getGuild(guild);
204216
if (err) {
205217
return res.status(500).json({ message: "Internal server error", err });
206218
}
207-
return res.status(200).json(data);
219+
return res.status(200).json({
220+
enabled: ((data?.updates_enabled ?? 1) === 1),
221+
channel: data?.updates_channel_id ?? null,
222+
});
208223
} catch (error) {
209224
return res.status(500).json({ message: "Internal server error" });
210225
}

bot/commands.ts

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import client from '.';
44
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, type CommandInteraction, ChannelType, type APIApplicationCommandOption, GuildMember, AttachmentBuilder, ComponentType } from 'discord.js';
55
import { heapStats } from 'bun:jsc';
6-
import { getGuildLeaderboard, makeGETRequest, getRoles, removeRole, addRole, enableUpdates, disableUpdates, getCooldown, setCooldown, checkIfGuildHasUpdatesEnabled } from './utils/requestAPI';
6+
import { getGuildLeaderboard, makeGETRequest, getRoles, removeRole, addRole, enableUpdates, disableUpdates, getCooldown, setCooldown, getUpdatesChannel, setUpdatesChannel } from './utils/requestAPI';
77
import convertToLevels from './utils/convertToLevels';
88
import quickEmbed from './utils/quickEmbed';
99
import { Font, RankCardBuilder } from 'canvacord';
@@ -161,7 +161,7 @@ const commands: Record<string, Command> = {
161161
.setDisplayName(member.displayName)
162162
.setAvatar(member.displayAvatarURL({ forceStatic: true, size: 4096 })) // user avatar
163163
.setCurrentXP(xp.xp) // current xp
164-
.setRequiredXP(xp.xp_needed_next_level) // required xp
164+
.setRequiredXP(xp.xp + xp.xp_needed_next_level) // required xp
165165
.setLevel(xp.level) // user level
166166
.setRank(rank) // user rank
167167
.setOverlay(member.user.banner ? 95 : 90) // overlay percentage. Overlay is a semi-transparent layer on top of the background
@@ -450,24 +450,37 @@ const commands: Record<string, Command> = {
450450
data: {
451451
options: [{
452452
name: 'action',
453-
description: 'Note that enabling is in THIS channel and will override the current updates channel!',
453+
description: 'Select an action',
454454
type: 3,
455455
required: true,
456456
choices: [
457457
{
458-
name: 'check',
458+
name: 'Check',
459459
value: 'check',
460460
},
461461
{
462-
name: 'enable',
462+
name: 'Enable',
463463
value: 'enable',
464464
},
465465
{
466-
name: 'disable',
466+
name: 'Disable',
467467
value: 'disable',
468-
}
468+
},
469+
{
470+
name: 'Set',
471+
value: 'set',
472+
},
473+
{
474+
name: 'Reset to Default',
475+
value: 'reset',
476+
},
469477
]
470-
},],
478+
},{
479+
name: 'channel',
480+
description: 'Enter the channel ID. Required for set action.',
481+
type: 7,
482+
required: false,
483+
}],
471484
name: 'updates',
472485
description: 'Get the latest updates on the bot!',
473486
integration_types: [0],
@@ -494,6 +507,14 @@ const commands: Record<string, Command> = {
494507
let data
495508

496509
switch (action) {
510+
case 'enable':
511+
success = await enableUpdates(interaction.guildId as string);
512+
if (!success) {
513+
await interaction.reply({ ephemeral: true, content: 'Error enabling updates for this server' }).catch(console.error);
514+
return;
515+
}
516+
await interaction.reply({ ephemeral: true, content: `Updates are now enabled for this server` }).catch(console.error);
517+
return;
497518
case 'disable':
498519
success = await disableUpdates(interaction.guildId as string);
499520
if (!success) {
@@ -502,22 +523,54 @@ const commands: Record<string, Command> = {
502523
}
503524
await interaction.reply({ ephemeral: true, content: 'Updates are now disabled for this server' }).catch(console.error);
504525
return;
505-
case 'enable':
506-
success = await enableUpdates(interaction.guildId as string, channelId as string);
526+
case 'set':
527+
if(!channelId) {
528+
await interaction.reply({ ephemeral: true, content: 'ERROR: Channel was not specified!' });
529+
return;
530+
}
531+
success = await setUpdatesChannel(interaction.guildId as string, channelId);
507532
if (!success) {
508-
await interaction.reply({ ephemeral: true, content: 'Error enabling updates for this server' }).catch(console.error);
533+
await interaction.reply({ ephemeral: true, content: 'Error setting updates channel for this server' }).catch(console.error);
509534
return;
510535
}
511-
await interaction.reply({ ephemeral: true, content: `Updates are now enabled for this server in <#${channelId}>` }).catch(console.error);
536+
await interaction.reply({ ephemeral: true, content: `Updates channel has been set to <#${channelId}>` }).catch(console.error);
512537
return;
538+
case 'reset':
539+
success = await setUpdatesChannel(interaction.guildId as string, null);
540+
if (!success) {
541+
await interaction.reply({ ephemeral: true, content: 'Error resetting updates channel for this server' }).catch(console.error);
542+
return;
543+
}
544+
await interaction.reply({ ephemeral: true, content: `Updates channel has been reset to default` }).catch(console.error);
545+
return
513546
default:
514-
data = await checkIfGuildHasUpdatesEnabled(interaction.guildId as string);
547+
data = await getUpdatesChannel(interaction.guildId as string);
515548
if (!data || Object.keys(data).length === 0) {
516549
await interaction.reply({ ephemeral: true, content: 'No data found' }).catch(console.error);
517550
return;
518551
}
519-
// TODO: Format in embed
520-
await interaction.reply({ ephemeral: true, content: JSON.stringify(data, null, 2) }).catch(console.error);
552+
await interaction.reply({
553+
embeds: [
554+
quickEmbed({
555+
color: 'Blurple',
556+
title: 'Updates',
557+
description: 'Updates for this server',
558+
}, interaction)
559+
.addFields(
560+
{
561+
name: 'Enabled',
562+
value: data.enabled ? 'Yes' : 'No',
563+
inline: true,
564+
},
565+
{
566+
name: 'Channel',
567+
value: data.channel ? `<#${data.channel}>` : 'N/A',
568+
inline: true,
569+
},
570+
)
571+
],
572+
ephemeral: true
573+
}).catch(console.error);
521574
return;
522575
}
523576
},

bot/events/messageCreate.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ client.on('messageCreate', async (message: Message) => {
99
if (message.author.bot) return;
1010

1111
const cooldownTime = (await getCooldown(message.guildId as string))?.cooldown ?? 30_000;
12-
12+
1313
const cooldown = cooldowns.get(message.author.id);
1414
if (cooldown && Date.now() - cooldown < cooldownTime) return;
1515

1616
const xpToGive: number = message.content.length;
1717
const pfp: string = message.member?.displayAvatarURL() ?? message.author.displayAvatarURL()
1818
const name: string = message.author.username;
1919
const nickname: string = message.member?.nickname ?? message.author.globalName ?? message.author.username;
20-
await makePOSTRequest(message.guildId as string, message.author.id, xpToGive, pfp, name, nickname);
20+
await makePOSTRequest(message.guildId as string, message.author.id, message.channel.id, xpToGive, pfp, name, nickname);
2121
cooldowns.set(message.author.id, Date.now());
2222

2323
const guildName = message.guild?.name;

0 commit comments

Comments
 (0)