Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/db/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export async function initTables() {
name VARCHAR(255),
icon VARCHAR(255),
members INT,
cooldown INT DEFAULT 30000,
updates_enabled BOOLEAN DEFAULT FALSE,
updates_channel VARCHAR(255)
)
Expand Down
3 changes: 2 additions & 1 deletion api/db/queries/guilds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ export interface Guild {
name: string;
icon: string;
members: number;
cooldown: number;
updates_enabled: boolean;
updates_channel: string;
}

export async function getGuild(guildId: string): Promise<[QueryError | null, Guild | null]> {
export async function getGuild(guildId: string): Promise<[QueryError, null] | [null, Guild | null]> {
return new Promise((resolve, reject) => {
pool.query("SELECT * FROM guilds WHERE id = ?", [guildId], (err, results) => {
if (err) {
Expand Down
53 changes: 53 additions & 0 deletions api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,36 @@ app.post("/admin/:action/:guild/:target", authMiddleware, async (req, res) => {
default:
return res.status(500).json({ message: "Internal server error" });
}
case "cooldown":
if (target !== "set" && target !== "get") {
return res.status(400).json({ message: "Illegal request" });
}

if(target === "set" && !extraData) {
return res.status(400).json({ message: "Illegal request" });
}

switch (target) {
case "get":
try {
const [err, data] = await getGuild(guild);
if(err) {
return res.status(500).json({ message: "Internal server error" });
}
return res.status(200).json({ cooldown: data?.cooldown ?? 30_000 });
} catch (error) {
return res.status(500).json({ message: "Internal server error" });
}
case "set":
try {
const data = await adminCooldownSet(guild, extraData.cooldown);
return res.status(200).json(data);
} catch (error) {
return res.status(500).json({ message: "Internal server error" });
}
default:
return res.status(500).json({ message: "Internal server error" });
}
default:
return res.status(400).json({ message: "Illegal request" });
}
Expand Down Expand Up @@ -392,3 +422,26 @@ async function adminUpdatesRemove(guildId: string) {
}

//#endregion

// TODO: actually implement this in a real way
//#region Admin: Cooldown
async function adminCooldownSet(guild: string, cooldown: number) {
const updateCooldownQuery = `
INSERT INTO guilds (id, cooldown) VALUES (?, ?)
ON DUPLICATE KEY UPDATE
cooldown = VALUES(cooldown)
`;

return new Promise((resolve, reject) => {
pool.query(updateCooldownQuery, [guild, cooldown], (err, results) => {
if (err) {
console.error("Error setting cooldown:", err);
reject(err);
} else {
resolve(results);
}
});
});
}

//#endregion
78 changes: 77 additions & 1 deletion bot/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import client from '.';
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, type CommandInteraction, ChannelType } from 'discord.js';
import { heapStats } from 'bun:jsc';
import { getGuildLeaderboard, makeGETRequest, getRoles, removeRole, addRole, enableUpdates, disableUpdates } from './utils/requestAPI';
import { getGuildLeaderboard, makeGETRequest, getRoles, removeRole, addRole, enableUpdates, disableUpdates, getCooldown, setCooldown } from './utils/requestAPI';
import convertToLevels from './utils/convertToLevels';
import quickEmbed from './utils/quickEmbed';

Expand Down Expand Up @@ -429,6 +429,82 @@ const commands: Record<string, Command> = {
return;
}
},
},
cooldown: {
data: {
options: [{
name: 'action',
id: 'action',
description: 'Select an action',
type: 3,
required: true,
choices: [
{
name: 'Get',
value: 'get',
},
{
name: 'Set',
value: 'set',
}
]
},{
name: 'cooldown',
id: 'cooldown',
description: 'Enter the cooldown in seconds. Required for set action.',
type: 4,
required: false,
choices: []
}],
name: 'cooldown',
description: 'Manage the cooldown for XP!',
integration_types: [0],
contexts: [0, 2],
},
execute: async (interaction) => {
if (!interaction.memberPermissions?.has('ManageChannels')) {
const errorEmbed = quickEmbed({
color: 'Red',
title: 'Error!',
description: 'Missing permissions: `Manage Channels`'
}, interaction);
await interaction.reply({
ephemeral: true,
embeds: [errorEmbed]
})
.catch(console.error);
return;
}

const action = interaction.options.get('action')?.value;
const cooldown = interaction.options.get('cooldown')?.value;

let cooldownData;
let apiSuccess;

switch (action) {
case 'get':
cooldownData = await getCooldown(interaction.guildId as string);
if (!cooldownData) {
await interaction.reply({ ephemeral: true, content: 'Error fetching cooldown data!' });
return;
}
await interaction.reply({ ephemeral: true, content: `Cooldown: ${(cooldownData?.cooldown ?? 30_000) / 1000} seconds` });
return;
case 'set':
if (!cooldown) {
await interaction.reply({ ephemeral: true, content: 'ERROR: Cooldown was not specified!' });
return;
}
apiSuccess = await setCooldown(interaction.guildId as string, parseInt(cooldown as string) * 1000);
if (!apiSuccess) {
await interaction.reply({ ephemeral: true, content: 'Error setting cooldown!' });
return;
}
await interaction.reply({ ephemeral: true, content: `Cooldown set to ${cooldown} seconds` });
return;
}
}
}
};

Expand Down
5 changes: 3 additions & 2 deletions bot/events/messageCreate.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Message } from 'discord.js';
import client from '../index';
import { makePOSTRequest, updateGuildInfo } from '../utils/requestAPI';
import { getCooldown, makePOSTRequest, updateGuildInfo } from '../utils/requestAPI';

const cooldowns = new Map<string, number>();
const cooldownTime = 30 * 1000;

// Run this event whenever a message has been sent
client.on('messageCreate', async (message: Message) => {
if (message.author.bot) return;

const cooldownTime = (await getCooldown(message.guildId as string))?.cooldown ?? 30_000;

const cooldown = cooldowns.get(message.author.id);
if (cooldown && Date.now() - cooldown < cooldownTime) return;
Expand Down
26 changes: 26 additions & 0 deletions bot/utils/requestAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,29 @@ export async function disableUpdates(guild: string) {
return response.status === 200;
}
//#endregion

//#region Cooldowns
export async function getCooldown(guild: string) {
const response = await fetch(`http://localhost:18103/admin/cooldown/${guild}/get`, {
"headers": {
'Content-Type': 'application/json',
'Authorization': process.env.AUTH as string,
},
"body": JSON.stringify({}),
"method": "POST"
});
return response.json();
}

export async function setCooldown(guild: string, cooldown: number) {
const response = await fetch(`http://localhost:18103/admin/cooldown/${guild}/set`, {
"headers": {
'Content-Type': 'application/json',
'Authorization': process.env.AUTH as string,
},
"body": JSON.stringify({ extraData: { cooldown } }),
"method": "POST"
});
return response.status === 200;
}
//#endregion