diff --git a/src/discord/utils/commandCooldown.ts b/src/discord/utils/commandCooldown.ts new file mode 100644 index 00000000..c866997c --- /dev/null +++ b/src/discord/utils/commandCooldown.ts @@ -0,0 +1,48 @@ +import { User, GuildMember } from 'discord.js'; + +// Map to store cooldowns for users and their commands +const cooldowns = new Map>(); + +/** + * commandCooldown + * @param {User | GuildMember} user The user or guild member + * @param {string} commandName The name of the command being executed + * @param {number} cooldownAmount The cooldown duration in milliseconds (default is 30 seconds) + * @return {Promise<{ success: boolean; message?: string }>} + */ +async function commandCooldown( + user: User | GuildMember, + commandName: string, + cooldownAmount: number = 30000, +): Promise<{ success: boolean; message?: string }> { + const now = Date.now(); + + // Ensure there's a map for the user in the cooldowns map + if (!cooldowns.has(user.id)) { + cooldowns.set(user.id, new Map()); + } + + const userCooldowns = cooldowns.get(user.id) as Map; + + // Check if the user has a cooldown for the specific command + const commandExpiration = userCooldowns.get(commandName); + if (commandExpiration) { + const expirationTime = commandExpiration + cooldownAmount; + + // If the cooldown is still active, inform the user + if (now < expirationTime) { + const timeLeft = (expirationTime - now) / 1000; // Time left in seconds + return { + success: false, + message: `Please wait ${timeLeft.toFixed(1)} more seconds before using this command or button again.`, + }; + } + } + + // Set or reset the cooldown for the specific command + userCooldowns.set(commandName, now); + + return { success: true }; +} + +export default commandCooldown; diff --git a/src/discord/utils/tripsitme.ts b/src/discord/utils/tripsitme.ts index 5e2efeff..ead1b5eb 100644 --- a/src/discord/utils/tripsitme.ts +++ b/src/discord/utils/tripsitme.ts @@ -35,6 +35,7 @@ import { ticket_status, user_tickets } from '@prisma/client'; import commandContext from './context'; import { embedTemplate } from './embedTemplate'; import { checkChannelPermissions, checkGuildPermissions } from './checkPermissions'; +import { commandCooldown } from './commandCooldown'; const F = f(__filename); @@ -837,6 +838,13 @@ export async function tripsitmeUserClose( if (!interaction.channel) return; log.info(F, await commandContext(interaction)); + const cooldown = await commandCooldown(interaction.user, interaction.customId); + + if (!cooldown.success && cooldown.message) { + await interaction.reply({ content: cooldown.message, ephemeral: true }); + return; + } + await interaction.deferReply({ ephemeral: false }); const targetId = interaction.customId.split('~')[1]; @@ -1182,6 +1190,12 @@ export async function tripSitMe( return null; } + const cooldown = await commandCooldown(interaction.user, interaction.customId); + + if (!cooldown.success && cooldown.message) { + await interaction.editReply(cooldown.message); + } + // const actor = interaction.member; const guildData = await db.discord_guilds.upsert({ where: { @@ -1462,6 +1476,13 @@ export async function tripsitmeButton( log.info(F, await commandContext(interaction)); const target = interaction.member as GuildMember; + const cooldown = await commandCooldown(interaction.user, interaction.customId); + + if (!cooldown.success && cooldown.message) { + await interaction.reply({ content: cooldown.message, ephemeral: true }); + return; + } + // log.debug(F, `target: ${JSON.stringify(target, n ull, 2)}`); // const actorIsAdmin = target.permissions.has(PermissionsBitField.Flags.Administrator); diff --git a/src/global/utils/timer.ts b/src/global/utils/timer.ts index 2591d035..2e63e9df 100644 --- a/src/global/utils/timer.ts +++ b/src/global/utils/timer.ts @@ -1075,9 +1075,12 @@ async function checkMoodle() { // eslint-disable-line }, ); // eslint-disable-line } - - member.roles.add(role); - log.info(F, `Gave ${member.user.username} the ${role.name} role`); + if (!member.roles.cache.has(env.ROLE_NEEDS_HELP)) { + member.roles.add(role); + log.info(F, `Gave ${member.user.username} the ${role.name} role`); + } else { + log.info(F, `Skipped giving ${member.user.username} the ${role.name} because they have the Needs Help role`); + } // eslint-disable max-len member.user.send({