button cooldowns

This commit is contained in:
Axel Olausson Holtenäs 2022-06-11 21:59:47 +02:00
parent e1ae56e360
commit 24e44f7235
No known key found for this signature in database
GPG key ID: 7BF6826B76382CBA
16 changed files with 173 additions and 263 deletions

View file

@ -1,5 +1,5 @@
// Dependencies
import { CommandInteraction, Message } from "discord.js";
import { CommandInteraction, ButtonInteraction, Message } from "discord.js";
import logger from "../../logger";
@ -7,7 +7,7 @@ import getEmbedConfig from "../../helpers/getEmbedConfig";
import timeoutSchema from "../../models/timeout";
import addSeconds from "../../helpers/addSeconds";
export const interaction = async (i: CommandInteraction, cooldown: number) => {
export const command = async (i: CommandInteraction, cooldown: number) => {
const { guild, user, commandId } = i;
// Check if user has a timeout
@ -56,12 +56,57 @@ export const interaction = async (i: CommandInteraction, cooldown: number) => {
});
};
export const message = async (
message: Message,
cooldown: number,
id: string
) => {
const { guild, member } = message;
export const button = async (i: ButtonInteraction, cooldown: number) => {
const { guild, user, customId } = i;
// Check if user has a timeout
const hasTimeout = await timeoutSchema.findOne({
guildId: guild?.id || "0",
userId: user.id,
cooldown: cooldown,
timeoutId: customId,
});
// If user is not on timeout
if (hasTimeout) {
const { guildId, userId, timeoutId, createdAt } = hasTimeout;
const overDue = (await addSeconds(cooldown, createdAt)) < new Date();
if (!overDue) {
const diff = Math.round(
(new Date(hasTimeout.createdAt).getTime() - new Date().getTime()) / 1000
);
throw new Error(
`You must wait ${diff} seconds before using this command.`
);
}
// Delete timeout
await timeoutSchema
.deleteOne({
guildId,
userId,
timeoutId,
cooldown,
})
.then(async () => {
logger.debug(
`Timeout document ${timeoutId} has been deleted from user ${userId}.`
);
});
}
// Create timeout
await timeoutSchema.create({
guildId: guild?.id || "0",
userId: user.id,
cooldown: cooldown,
timeoutId: customId,
});
};
export const message = async (msg: Message, cooldown: number, id: string) => {
const { guild, member } = msg;
if (!guild) throw new Error("Guild is undefined");
if (!member) throw new Error("Member is undefined");

View file

@ -1,25 +1,26 @@
import { CommandInteraction, MessageEmbed } from "discord.js";
import { Interaction, MessageEmbed } from "discord.js";
import getEmbedConfig from "../../helpers/getEmbedConfig";
export default async (interaction: CommandInteraction, ephemeral: boolean) => {
export default async (interaction: Interaction, ephemeral: boolean) => {
if (!interaction.isRepliable())
throw new Error(`Cannot reply to an interaction that is not repliable`);
await interaction.deferReply({
ephemeral,
});
const { waitColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const embedConfig = await getEmbedConfig(interaction.guild);
await interaction.editReply({
embeds: [
new MessageEmbed()
.setFooter({
text: footerText,
iconURL: footerIcon,
text: embedConfig.footerText,
iconURL: embedConfig.footerIcon,
})
.setTimestamp(new Date())
.setTitle("Processing your request")
.setColor(waitColor)
.setColor(embedConfig.waitColor)
.setDescription("Please wait..."),
],
});

View file

@ -4,7 +4,7 @@ import { Client } from "discord.js";
import * as roles from "./modules/roles";
export const options = {
schedule: "*/5 * * * * *", // https://crontab.guru/
schedule: "*/5 * * * *", // https://crontab.guru/
};
export const execute = async (client: Client) => {

View file

@ -4,7 +4,7 @@ import { IEncryptionData } from "../interfaces/EncryptionData";
export interface IApi {
guildId: Snowflake;
url: string;
url: IEncryptionData;
token: IEncryptionData;
}
@ -17,11 +17,18 @@ const apiSchema = new Schema<IApi>(
index: true,
},
url: {
type: String,
required: true,
unique: false,
index: true,
default: "https://localhost/api/",
iv: {
type: String,
required: true,
unique: false,
index: true,
},
content: {
type: String,
required: true,
unique: false,
index: true,
},
},
token: {
iv: {
@ -29,14 +36,12 @@ const apiSchema = new Schema<IApi>(
required: true,
unique: false,
index: true,
default: "token",
},
content: {
type: String,
required: true,
unique: false,
index: true,
default: "token",
},
},
},

View file

@ -54,7 +54,7 @@ export default {
embeds: [
embed
.setDescription(
`Below are the top 10 users in this guild.
`Below are the top ten members in this guild.
${topTen.map(entry).join("\n")}
`

View file

@ -45,7 +45,7 @@ export default {
const guildDB = await fetchGuild(guild);
await cooldown.interaction(interaction, guildDB?.credits?.workTimeout);
await cooldown.command(interaction, guildDB?.credits?.workTimeout);
const creditsEarned = chance.integer({
min: 0,

View file

@ -75,14 +75,16 @@ export default {
if (!apiCredentials) return;
const url = encryption.decrypt(apiCredentials?.url);
const api = axios?.create({
baseURL: `${apiCredentials?.url}/api/`,
baseURL: `${url}/api/`,
headers: {
Authorization: `Bearer ${encryption.decrypt(apiCredentials.token)}`,
},
});
const shopUrl = `${apiCredentials?.url}/store`;
const shopUrl = `${url}/store`;
await api
.post("vouchers", {

View file

@ -52,7 +52,7 @@ export default {
await noSelfReputation(optionTarget, user);
// Check if user is on cooldown otherwise create one
await cooldown.interaction(interaction, timeout);
await cooldown.command(interaction, timeout);
switch (optionType) {
case "positive":

View file

@ -153,15 +153,16 @@ export default {
});
if (!apiCredentials) return;
const url = encryption.decrypt(apiCredentials?.url);
const api = axios?.create({
baseURL: `${apiCredentials.url}/api/`,
baseURL: `${url}/api/`,
headers: {
Authorization: `Bearer ${encryption.decrypt(apiCredentials.token)}`,
},
});
const shopUrl = `${apiCredentials?.url}/store`;
const shopUrl = `${url}/store`;
const buttons = new MessageActionRow().addComponents(
new MessageButton()

View file

@ -1,51 +0,0 @@
import { CommandInteraction, MessageEmbed } from "discord.js";
import * as cooldown from "../../../../helpers/cooldown";
import logger from "../../../../logger";
export default async (
interaction: CommandInteraction,
metadata: any,
embedConfig: any
) => {
if (
metadata.permissions &&
metadata.guildOnly &&
!interaction.memberPermissions?.has(metadata.permissions)
) {
return interaction?.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:x:] Permission")
.setDescription(`You do not have the permission to manage the bot.`)
.setTimestamp(new Date())
.setColor(embedConfig.errorColor)
.setFooter({
text: embedConfig.footerText,
iconURL: embedConfig.footerIcon,
}),
],
});
}
logger.info(metadata);
if (metadata.cooldown) {
await cooldown
.interaction(interaction, metadata.cooldown)
.catch(async (error) => {
throw new Error("Cooldown error: " + error);
});
}
if (metadata.guildOnly) {
if (!interaction.guild) {
throw new Error("This command is guild only.");
}
}
if (metadata.dmOnly) {
if (interaction.guild) {
throw new Error("This command is DM only.");
}
}
};

View file

@ -1,123 +0,0 @@
// Dependencies
import { CommandInteraction, MessageEmbed } from "discord.js";
import logger from "../../../../logger";
import deferReply from "../../../../helpers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedConfig";
import capitalizeFirstLetter from "../../../../helpers/capitalizeFirstLetter";
import * as cooldown from "../../../../helpers/cooldown";
export default async (interaction: CommandInteraction) => {
if (!interaction.isButton()) return;
const { errorColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { guild, customId, user, memberPermissions } = interaction;
const currentButton = await import(`../../../buttons/${customId}`);
if (currentButton == null) {
logger.silly(`Button ${customId} not found`);
}
const metadata = currentButton.metadata;
await deferReply(interaction, metadata.ephemeral || false);
if (metadata.guildOnly) {
if (!guild) {
logger.debug(`Guild is null`);
return interaction.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:x:] Permission")
.setDescription("This command is only available for guild")
.setColor(errorColor)
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
}
if (
metadata.permissions &&
metadata.guildOnly &&
!memberPermissions?.has(metadata.permissions)
) {
return interaction?.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:x:] Permission")
.setDescription(`You do not have the permission to manage the bot.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
if (metadata.dmOnly) {
if (guild) {
logger.silly(`Guild exist`);
return interaction.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:x:] Permission")
.setDescription("This command is only available in DM.")
.setColor(errorColor)
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
}
if (metadata.cooldown) {
await cooldown
.interaction(interaction, metadata.cooldown)
.catch(async (error) => {
return interaction?.editReply({
embeds: [
new MessageEmbed()
.setTitle("[:x:] Permission")
.setDescription(`${error}`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
});
}
await currentButton
.execute(interaction)
.then(async () => {
return logger?.silly(
`Button: ${customId} executed in guild: ${guild?.name} (${guild?.id}) by user: ${user?.tag} (${user?.id})`
);
})
.catch(async (error: string) => {
logger?.debug(`INTERACTION BUTTON CATCH: ${error}`);
return interaction.editReply({
embeds: [
new MessageEmbed()
.setTitle(
`[:x:] ${capitalizeFirstLetter(
interaction.options.getSubcommand()
)}`
)
.setDescription(`${"``"}${error}${"``"}`)
.setColor(errorColor)
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
});
};

View file

@ -1,48 +0,0 @@
// Dependencies
import { CommandInteraction, MessageEmbed } from "discord.js";
import logger from "../../../../logger";
import deferReply from "../../../../helpers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedConfig";
import getCommandMetadata from "../../../../helpers/getCommandMetadata";
import capitalizeFirstLetter from "../../../../helpers/capitalizeFirstLetter";
import * as cooldown from "../../../../helpers/cooldown";
export default async (interaction: CommandInteraction) => {
if (!interaction.isCommand()) return;
const { errorColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
);
const { client, guild, commandName, user, memberPermissions } = interaction;
const currentCommand = client.commands.get(commandName);
if (currentCommand == null) {
logger.silly(`Command ${commandName} not found`);
}
const metadata = await getCommandMetadata(interaction, currentCommand);
await deferReply(interaction, metadata.ephemeral || false);
if (metadata.guildOnly && !guild)
throw new Error("This command is guild only.");
if (
metadata.permissions &&
metadata.guildOnly &&
!memberPermissions?.has(metadata.permissions)
)
throw new Error("You don't have the required permissions");
if (metadata.dmOnly && guild)
throw new Error("This command is only available in DM");
if (metadata.cooldown)
await cooldown.interaction(interaction, metadata.cooldown);
await currentCommand.execute(interaction);
};

View file

@ -0,0 +1,36 @@
// Dependencies
import { Interaction } from "discord.js";
import deferReply from "../../../../../helpers/deferReply";
import * as cooldown from "../../../../../helpers/cooldown";
export default async (interaction: Interaction) => {
if (!interaction.isButton()) return;
const { guild, customId, memberPermissions } = interaction;
const currentButton = await import(`../../../buttons/${customId}`);
if (!currentButton) throw new Error(`Unknown button ${customId}`);
const metadata = currentButton.metadata;
await deferReply(interaction, metadata.ephemeral || false);
if (metadata.guildOnly && !guild)
throw new Error("This command is guild only.");
if (
metadata.permissions &&
metadata.guildOnly &&
!memberPermissions?.has(metadata.permissions)
)
throw new Error("You don't have the required permissions");
if (metadata.dmOnly && guild)
throw new Error("This command is only available in DM");
if (metadata.cooldown) await cooldown.button(interaction, metadata.cooldown);
await currentButton.execute(interaction);
};

View file

@ -0,0 +1,34 @@
// Dependencies
import { Interaction } from "discord.js";
import deferReply from "../../../../../helpers/deferReply";
import getCommandMetadata from "../../../../../helpers/getCommandMetadata";
import * as cooldown from "../../../../../helpers/cooldown";
export default async (interaction: Interaction) => {
if (!interaction.isCommand()) return;
const { client, commandName } = interaction;
const currentCommand = client.commands.get(commandName);
if (!currentCommand) throw new Error(`Unknown command ${commandName}`);
const metadata = await getCommandMetadata(interaction, currentCommand);
await deferReply(interaction, metadata.ephemeral || false);
if (metadata.guildOnly && !interaction.guild)
throw new Error("This command is guild only.");
if (
metadata.permissions &&
metadata.guildOnly &&
!interaction.memberPermissions?.has(metadata.permissions)
)
throw new Error("You don't have the required permissions");
if (metadata.dmOnly && interaction.guild)
throw new Error("This command is only available in DM");
if (metadata.cooldown) await cooldown.command(interaction, metadata.cooldown);
await currentCommand.execute(interaction);
};

View file

@ -0,0 +1,11 @@
import { Interaction } from "discord.js";
import button from "./button";
import command from "./command";
import logger from "../../../../logger";
export const execute = async (interaction: Interaction) => {
await button(interaction);
await command(interaction);
};

View file

@ -2,8 +2,8 @@
import { CommandInteraction, MessageEmbed } from "discord.js";
// Dependencies
import isCommand from "../../events/interactionCreate/components/isCommand";
import isButton from "../../events/interactionCreate/components/isButton";
import * as handlers from "./handlers";
import logger from "../../../logger";
import audits from "./audits";
import { IEventOptions } from "../../../interfaces/EventOptions";
@ -27,11 +27,8 @@ export const execute = async (interaction: CommandInteraction) => {
await audits.execute(interaction);
try {
await isCommand(interaction);
await isButton(interaction);
} catch (error) {
logger.debug(`${error}`);
await handlers.execute(interaction).catch(async (err) => {
logger.debug(`${err}`);
return interaction.editReply({
embeds: [
@ -41,11 +38,11 @@ export const execute = async (interaction: CommandInteraction) => {
interaction.options.getSubcommand()
)}`
)
.setDescription(`${"``"}${error}${"``"}`)
.setDescription(`${"``"}${err}${"``"}`)
.setColor(errorColor)
.setTimestamp(new Date())
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
});
};