Merge pull request #462 from VermiumSifell/dev

Refactoring some handlers and middlewares
This commit is contained in:
Axel Olausson Holtenäs 2022-10-24 11:14:02 +02:00 committed by GitHub
commit 8257f0e137
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 567 additions and 934 deletions

19
package-lock.json generated
View file

@ -16,6 +16,7 @@
"chance": "^1.1.8",
"common": "^0.2.5",
"crypto": "^1.0.1",
"date-fns": "^2.29.3",
"discord-api-types": "^0.37.0",
"discord.js": "^14.0.0",
"dotenv": "^16.0.1",
@ -25,6 +26,7 @@
"i18next-fs-backend": "^1.1.4",
"i18next-http-backend": "^1.4.0",
"i18next-resources-to-backend": "^1.0.0",
"moment": "^2.29.4",
"mongoose": "^6.2.3",
"node-schedule": "^2.1.0",
"ts-node": "^10.7.0",
@ -2647,6 +2649,18 @@
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in."
},
"node_modules/date-fns": {
"version": "2.29.3",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
"integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==",
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -9706,6 +9720,11 @@
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig=="
},
"date-fns": {
"version": "2.29.3",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
"integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA=="
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",

View file

@ -4,7 +4,7 @@
"description": "Earn credits while chatting! And more",
"main": "dist/index.js",
"scripts": {
"dev": "tsc --watch & nodemon dist",
"dev": "tsc --watch & NODE_ENV=development nodemon dist",
"build": "tsc -p .",
"prisma:generate": "prisma generate",
"test": "jest",
@ -40,6 +40,7 @@
"chance": "^1.1.8",
"common": "^0.2.5",
"crypto": "^1.0.1",
"date-fns": "^2.29.3",
"discord-api-types": "^0.37.0",
"discord.js": "^14.0.0",
"dotenv": "^16.0.1",
@ -49,6 +50,7 @@
"i18next-fs-backend": "^1.1.4",
"i18next-http-backend": "^1.4.0",
"i18next-resources-to-backend": "^1.0.0",
"moment": "^2.29.4",
"mongoose": "^6.2.3",
"node-schedule": "^2.1.0",
"ts-node": "^10.7.0",

View file

@ -5,7 +5,7 @@ import {
import deferReply from "../../../../handlers/deferReply";
import { success as BaseEmbedSuccess } from "../../../../helpers/baseEmbeds";
import { transfer as CreditsTransfer } from "../../../../helpers/credits";
import creditsTransfer from "../../../../helpers/credits/transfer";
// 1. Export a builder function.
export const builder = (command: SlashCommandSubcommandBuilder) => {
@ -55,7 +55,7 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
const EmbedSuccess = await BaseEmbedSuccess(guild, "[:dollar:] Gift");
// 5. Start an transaction of the credits.
await CreditsTransfer(guild, user, target, credits);
await creditsTransfer(guild, user, target, credits);
// 6. Tell the target that they have been gifted credits.
await target.send({

View file

@ -2,10 +2,11 @@ import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import Chance from "chance";
import { CommandInteraction } from "discord.js";
import { command as CooldownCommand } from "../../../../handlers/cooldown";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import { success as BaseEmbedSuccess } from "../../../../helpers/baseEmbeds";
import creditsGive from "../../../../helpers/credits/give";
import cooldown from "../../../../middlewares/cooldown";
import logger from "../../../../middlewares/logger";
// 1. Export a builder function.
@ -19,7 +20,7 @@ export const execute = async (interaction: CommandInteraction) => {
await deferReply(interaction, true);
// 2. Destructure interaction object.
const { guild, user } = interaction;
const { guild, user, commandId } = interaction;
if (!guild) throw new Error("Guild not found");
if (!user) throw new Error("User not found");
@ -43,7 +44,7 @@ export const execute = async (interaction: CommandInteraction) => {
if (!createGuild) throw new Error("Guild not found");
// 6. Create a cooldown for the user.
await CooldownCommand(interaction, createGuild.creditsWorkTimeout);
await cooldown(guild, user, commandId, createGuild.creditsWorkTimeout);
// 6. Generate a random number between 0 and creditsWorkRate.
const creditsEarned = chance.integer({
@ -51,51 +52,13 @@ export const execute = async (interaction: CommandInteraction) => {
max: createGuild.creditsWorkRate,
});
// 7. Upsert the guildMember in the database.
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
update: { creditsEarned: { increment: creditsEarned } },
create: {
creditsEarned,
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
include: {
user: true,
guild: true,
},
});
logger.silly(createGuildMember);
if (!createGuildMember) throw new Error("GuildMember not found");
const upsertGuildMember = await creditsGive(guild, user, creditsEarned);
// 8. Send embed.
await interaction.editReply({
embeds: [
EmbedSuccess.setDescription(
`You worked and earned **${creditsEarned}** credits! You now have **${createGuildMember.creditsEarned}** credits. :tada:`
`You worked and earned **${creditsEarned}** credits! You now have **${upsertGuildMember.creditsEarned}** credits. :tada:`
),
],
});

View file

@ -1,9 +1,9 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import axios from "axios";
import { CommandInteraction, EmbedBuilder } from "discord.js";
import { command as CooldownCommand } from "../../../../handlers/cooldown";
import deferReply from "../../../../handlers/deferReply";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import cooldown from "../../../../middlewares/cooldown";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
@ -13,9 +13,11 @@ export default {
execute: async (interaction: CommandInteraction) => {
await deferReply(interaction, false);
await CooldownCommand(interaction, 15);
const { guild, user, commandId } = interaction;
if (!guild) throw new Error("Guild not found");
if (!user) throw new Error("User not found");
const { guild } = interaction;
await cooldown(guild, user, commandId, 15);
const embedConfig = await getEmbedConfig(guild);

View file

@ -1,21 +1,12 @@
// Dependencies
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import logger from "../../../../../../middlewares/logger";
// Configurations
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
// Helpers../../../../../../../helpers/userData
import pluralize from "../../../../../../helpers/pluralize";
// Models
// Handlers
import prisma from "../../../../../../handlers/database";
import { ChatInputCommandInteraction, PermissionsBitField } from "discord.js";
import deferReply from "../../../../../../handlers/deferReply";
import { success as baseEmbedSuccess } from "../../../../../../helpers/baseEmbeds";
import checkPermission from "../../../../../../helpers/checkPermission";
// Function
import creditsGive from "../../../../../../helpers/credits/give";
import pluralize from "../../../../../../helpers/pluralize";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
@ -34,81 +25,41 @@ export default {
.setRequired(true)
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
// 1. Defer reply as ephemeral.
await deferReply(interaction, true);
// 2. Check if the user has the MANAGE_GUILD permission.
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { successColor, footerText, footerIcon } = await getEmbedConfig(
interaction.guild
); // Destructure
// 3. Destructure interaction object.
const { guild, options } = interaction;
if (!guild)
throw new Error("We could not get the current guild from discord.");
if (!options) throw new Error("We could not get the options from discord.");
const discordReceiver = options?.getUser("user");
const creditAmount = options?.getInteger("amount");
// If amount option is null
if (creditAmount === null)
// 4. Get the user and amount from the options.
const discordReceiver = options.getUser("user");
const creditsAmount = options.getInteger("amount");
if (typeof creditsAmount !== "number")
throw new Error("You need to provide a credit amount.");
// If amount is zero or below
if (creditAmount <= 0)
throw new Error("You must provide a credit amount greater than zero");
if (discordReceiver === null)
if (!discordReceiver)
throw new Error("We could not get the receiving user from Discord");
if (guild === null)
throw new Error("We could not get the current guild from discord.");
// 5. Create base embeds.
const embedSuccess = await baseEmbedSuccess(guild, "[:toolbox:] Give");
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: discordReceiver.id,
guildId: guild.id,
},
},
update: { creditsEarned: { increment: creditAmount } },
create: {
creditsEarned: creditAmount,
user: {
connectOrCreate: {
create: {
id: discordReceiver.id,
},
where: {
id: discordReceiver.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
});
// 6. Give the credits.
await creditsGive(guild, discordReceiver, creditsAmount);
logger.silly(createGuildMember);
// Save toUser
await interaction?.editReply({
// 7. Send embed.
return await interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Give)")
.setDescription(
`Successfully gave ${pluralize(creditAmount, "credit")}`
)
.setTimestamp(new Date())
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
embedSuccess.setDescription(
`Successfully gave ${pluralize(creditsAmount, "credit")}`
),
],
});
return;
},
};

View file

@ -1,21 +1,14 @@
// Dependencies
// Helpers
// Models
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
SlashCommandSubcommandBuilder,
} from "discord.js";
// Configurations
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
// Handlers
import prisma from "../../../../../../handlers/database";
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
import logger from "../../../../../../middlewares/logger";
// Function
import deferReply from "../../../../../../handlers/deferReply";
import { success as baseEmbedSuccess } from "../../../../../../helpers/baseEmbeds";
import checkPermission from "../../../../../../helpers/checkPermission";
import creditsSet from "../../../../../../helpers/credits/set";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
@ -35,107 +28,35 @@ export default {
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
// 1. Defer reply as ephemeral.
await deferReply(interaction, true);
// 2. Check if the user has the permission to manage the guild.
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { errorColor, successColor, footerText, footerIcon } =
await getEmbedConfig(interaction.guild);
// 3. Destructure interaction object.
const { options, guild } = interaction;
if (!guild) throw new Error(`We could not find this guild.`);
if (!options) throw new Error(`We could not find the options.`);
// 4. Get the user and amount from the options.
const discordUser = options.getUser("user");
const creditAmount = options.getInteger("amount");
if (typeof creditAmount !== "number") throw new Error("Amount is not set.");
if (!discordUser) throw new Error("User is not specified");
// If amount is null
if (creditAmount === null) {
logger?.silly(`Amount is null`);
// 5. Set the credits.
await creditsSet(guild, discordUser, creditAmount);
return interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(`You must provide an amount.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
// 6. Create base embeds.
const embedSuccess = await baseEmbedSuccess(guild, "[:toolbox:] Set");
if (discordUser === null) {
logger?.silly(`User is null`);
return interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(`You must provide a user.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
if (guild === null) {
logger?.silly(`Guild is null`);
return interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(`You must provide a guild.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: discordUser.id,
guildId: guild.id,
},
},
update: { creditsEarned: creditAmount },
create: {
creditsEarned: creditAmount,
user: {
connectOrCreate: {
create: {
id: discordUser.id,
},
where: {
id: discordUser.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
});
logger.silly(createGuildMember);
return interaction?.editReply({
// 7. Send embed.
return await interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Set)")
.setDescription(
`Set **${discordUser}**'s credits to **${creditAmount}**.`
)
.setTimestamp(new Date())
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
embedSuccess.setDescription(
`Set **${discordUser}**'s credits to **${creditAmount}**.`
),
],
});
},

View file

@ -1,22 +1,15 @@
// Dependencies
// Models
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
SlashCommandSubcommandBuilder,
} from "discord.js";
// Configurations
import getEmbedConfig from "../../../../../../helpers/getEmbedData";
// Helpers../../../../../../../helpers/userData
import pluralize from "../../../../../../helpers/pluralize";
// Handlers
import prisma from "../../../../../../handlers/database";
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
import logger from "../../../../../../middlewares/logger";
// Function
import deferReply from "../../../../../../handlers/deferReply";
import { success as baseEmbedSuccess } from "../../../../../../helpers/baseEmbeds";
import checkPermission from "../../../../../../helpers/checkPermission";
import creditsTake from "../../../../../../helpers/credits/take";
import pluralize from "../../../../../../helpers/pluralize";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
return command
@ -36,127 +29,36 @@ export default {
);
},
execute: async (interaction: ChatInputCommandInteraction) => {
// 1. Defer reply as ephemeral.
await deferReply(interaction, true);
// 2. Check if the user has the MANAGE_GUILD permission.
checkPermission(interaction, PermissionsBitField.Flags.ManageGuild);
const { errorColor, successColor, footerText, footerIcon } =
await getEmbedConfig(interaction.guild); // Destructure
// 3. Destructure interaction object.
const { guild, options } = interaction;
if (!guild) throw new Error("Invalid guild.");
if (!options) throw new Error("Invalid options.");
// User option
const discordReceiver = options?.getUser("user");
// 4. Get the user and amount from the options.
const discordReceiver = options.getUser("user");
const optionAmount = options.getInteger("amount");
if (typeof optionAmount !== "number") throw new Error("Invalid amount.");
if (!discordReceiver) throw new Error("Invalid user.");
// Amount option
const optionAmount = options?.getInteger("amount");
// 5. Create base embeds.
const embedSuccess = await baseEmbedSuccess(guild, "[:toolbox:] Take");
// If amount is null
if (optionAmount === null) {
logger?.silly(`Amount is null`);
// 6. Take the credits.
await creditsTake(guild, discordReceiver, optionAmount);
return interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`You must provide an amount.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
// If amount is zero or below
if (optionAmount <= 0) {
logger?.silly(`Amount is zero or below`);
return interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`You must provide an amount greater than zero.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
if (discordReceiver === null) {
logger?.silly(`Discord receiver is null`);
return interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`You must provide a user.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
if (guild === null) {
logger?.silly(`Guild is null`);
return interaction?.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(`You must be in a guild.`)
.setTimestamp(new Date())
.setColor(errorColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
],
});
}
const createGuildMember = await prisma.guildMember.upsert({
where: {
userId_guildId: {
userId: discordReceiver.id,
guildId: guild.id,
},
},
update: { creditsEarned: { decrement: optionAmount } },
create: {
creditsEarned: -optionAmount,
user: {
connectOrCreate: {
create: {
id: discordReceiver.id,
},
where: {
id: discordReceiver.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
},
});
logger.silly(createGuildMember);
await interaction?.editReply({
// 7. Send embed.
return await interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle("[:toolbox:] Manage - Credits (Take)")
.setDescription(
`Took ${pluralize(optionAmount, "credit")} from ${discordReceiver}.`
)
.setTimestamp(new Date())
.setColor(successColor)
.setFooter({ text: footerText, iconURL: footerIcon }),
embedSuccess.setDescription(
`Took ${pluralize(optionAmount, "credit")} from ${discordReceiver}.`
),
],
});
return;
},
};

View file

@ -6,7 +6,7 @@ import {
EmbedBuilder,
PermissionsBitField,
} from "discord.js";
import { transfer as CreditsTransfer } from "../../../../../../helpers/credits";
import creditsTransfer from "../../../../../../helpers/credits/transfer";
// Configurations
import deferReply from "../../../../../../handlers/deferReply";
import checkPermission from "../../../../../../helpers/checkPermission";
@ -65,7 +65,7 @@ export default {
if (!optionToUser)
throw new Error("You must provide a user to transfer to.");
await CreditsTransfer(guild, optionFromUser, optionToUser, optionAmount);
await creditsTransfer(guild, optionFromUser, optionToUser, optionAmount);
return interaction?.editReply({
embeds: [

View file

@ -1,12 +1,12 @@
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js";
import { command as CooldownCommand } from "../../../../handlers/cooldown";
import getEmbedConfig from "../../../../helpers/getEmbedData";
import logger from "../../../../middlewares/logger";
import noSelfReputation from "./components/noSelfReputation";
import prisma from "../../../../handlers/database";
import deferReply from "../../../../handlers/deferReply";
import cooldown from "../../../../middlewares/cooldown";
export default {
builder: (command: SlashCommandSubcommandBuilder) => {
@ -36,7 +36,7 @@ export default {
execute: async (interaction: ChatInputCommandInteraction) => {
await deferReply(interaction, true);
const { options, user, guild } = interaction;
const { options, user, guild, commandId } = interaction;
const { successColor, footerText, footerIcon } = await getEmbedConfig(
guild
@ -52,8 +52,10 @@ export default {
noSelfReputation(optionTarget, user);
// Check if user is on cooldown otherwise create one
await CooldownCommand(
interaction,
await cooldown(
guild,
user,
commandId,
parseInt(process.env.REPUTATION_TIMEOUT)
);

View file

@ -1,35 +1,14 @@
// Dependencies
import { BaseInteraction } from "discord.js";
import { button as CooldownButton } from "../../../../handlers/cooldown";
import deferReply from "../../../../handlers/deferReply";
export default async (interaction: BaseInteraction) => {
if (!interaction.isButton()) return;
const { guild, customId, memberPermissions } = interaction;
const { customId } = 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 CooldownButton(interaction, metadata.cooldown);
await currentButton.execute(interaction);
};

View file

@ -8,24 +8,5 @@ export default async (interaction: ChatInputCommandInteraction) => {
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.dmOnly && interaction.guild)
// throw new Error("This command is only available in DM");
// if (
// metadata.permissions &&
// metadata.guildOnly &&
// !interaction.memberPermissions?.has(metadata.permissions)
// )
// throw new Error("You don't have the required permissions");
// if (metadata.cooldown) {
// await CooldownCommand(interaction, metadata.cooldown);
// }
await currentCommand.execute(interaction);
};

View file

@ -1,6 +1,7 @@
import { ChannelType, Message } from "discord.js";
import { message as CooldownMessage } from "../../../../handlers/cooldown";
import prisma from "../../../../handlers/database";
import creditsGive from "../../../../helpers/credits/give";
import cooldown from "../../../../middlewares/cooldown";
import logger from "../../../../middlewares/logger";
export default {
@ -51,30 +52,14 @@ export default {
if (content.length < createGuildMember.guild.creditsMinimumLength) return;
const isOnCooldown = await CooldownMessage(
message,
await cooldown(
guild,
author,
"event-messageCreate-credits",
createGuildMember.guild.creditsTimeout,
"messageCreate-credits"
true
);
if (isOnCooldown) return;
const updateGuildMember = await prisma.guildMember.update({
where: {
userId_guildId: {
userId: author.id,
guildId: guild.id,
},
},
data: {
creditsEarned: {
increment: createGuildMember.guild.creditsRate,
},
},
});
logger.silly(updateGuildMember);
if (!updateGuildMember)
throw new Error("Failed to update guildMember object");
await creditsGive(guild, author, createGuildMember.guild.creditsRate);
},
};

View file

@ -1,6 +1,6 @@
import { ChannelType, Message } from "discord.js";
import { message as CooldownMessage } from "../../../../handlers/cooldown";
import prisma from "../../../../handlers/database";
import cooldown from "../../../../middlewares/cooldown";
import logger from "../../../../middlewares/logger";
export default {
@ -51,12 +51,13 @@ export default {
if (content.length < createGuildMember.guild.pointsMinimumLength) return;
const isOnCooldown = await CooldownMessage(
message,
await cooldown(
guild,
author,
"event-messageCreate-points",
createGuildMember.guild.pointsTimeout,
"messageCreate-points"
true
);
if (isOnCooldown) return;
const updateGuildMember = await prisma.guildMember.update({
where: {

View file

@ -2,7 +2,6 @@
import { Client } from "discord.js";
// Helpers
import deployCommands from "../../handlers/deployCommands";
import devMode from "../../handlers/devMode";
import updatePresence from "../../handlers/updatePresence";
import { IEventOptions } from "../../interfaces/EventOptions";
import logger from "../../middlewares/logger";
@ -16,6 +15,5 @@ export const execute = async (client: Client) => {
logger.info("Discord's API client is ready!");
updatePresence(client);
await devMode(client);
await deployCommands(client);
};

View file

@ -1,54 +1,36 @@
/* eslint-disable no-loops/no-loops */
import { Client } from "discord.js";
import listDir from "../../helpers/checkDirectory";
import checkDirectory from "../../helpers/checkDirectory";
import { ICommand } from "../../interfaces/Command";
import logger from "../../middlewares/logger";
// Register the commands.
export const register = async (client: Client) => {
// Get name of directories containing commands
const commandNames = await listDir("commands");
if (!commandNames) throw new Error("📦 No commands available");
logger.info("🔧 Started command management");
const amountOfCommands = commandNames.length;
let importedCommandAmount = 0;
logger.info(`📦 Trying to load ${amountOfCommands} commands`);
const commandNames = await checkDirectory("commands");
if (!commandNames) return logger.warn("No available commands found");
const importCommand = async (commandName: string) => {
// Import command from commands
const command: ICommand = await import(`../../commands/${commandName}`);
if (!command)
throw new Error(`📦 No command found while importing "${commandName}"`);
if (!command.builder)
throw new Error(
`📦 No command builder found while importing "${commandName}"`
);
const totalCommands = commandNames.length;
let loadedCommands = 0;
logger.info(`🔧 Loading ${totalCommands} commands`);
// Import an command.
const importCommand = async (name: string) => {
const command: ICommand = await import(`../../commands/${name}`);
// Add command to collection
client.commands.set(command.builder.name, command);
importedCommandAmount += 1;
loadedCommands++;
};
// Send log message when it's done loading commands
const doneImporting = () => {
if (importedCommandAmount !== amountOfCommands) {
return logger.warn(
`📦 Failed importing ${
amountOfCommands - importedCommandAmount
} of ${amountOfCommands} commands`
);
}
return logger.info(`📦 Managed to load all commands`);
};
// Start importing commands
commandNames.forEach(async (commandName: string, index: number) => {
for await (const commandName of commandNames) {
await importCommand(commandName).then(() => {
logger.debug(`📦 Imported the "${commandName}" command`);
logger.verbose(`🔧 Loaded command "${commandName}"`);
});
// If done importing
if (index + 1 === amountOfCommands) {
await doneImporting();
if (loadedCommands === totalCommands) {
logger.info("🔧 All commands loaded");
}
});
}
};

View file

@ -1,277 +0,0 @@
// Dependencies
import { ButtonInteraction, CommandInteraction, Message } from "discord.js";
import addSeconds from "../../helpers/addSeconds";
import logger from "../../middlewares/logger";
import prisma from "../database";
// Command cooldown
export const command = async (i: CommandInteraction, cooldown: number) => {
const { guild, user, commandId } = i;
if (!guild) throw new Error("Guild not found");
// Check if user has a timeout
const hasTimeout = await prisma.cooldown.findUnique({
where: {
guildId_userId_timeoutId: {
guildId: guild.id,
userId: user.id,
timeoutId: commandId,
},
},
});
logger.silly(hasTimeout);
// If user is not on timeout
if (hasTimeout) {
const { userId, timeoutId, createdAt } = hasTimeout;
const overDue = 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
const deleteCooldown = await prisma.cooldown.delete({
where: {
guildId_userId_timeoutId: {
guildId: guild.id,
userId: user.id,
timeoutId: commandId,
},
},
});
logger.silly(deleteCooldown);
logger.debug(
`Timeout document ${timeoutId} has been deleted from user ${userId}.`
);
}
// Create timeout
const createCooldown = await prisma.cooldown.upsert({
where: {
guildId_userId_timeoutId: {
userId: user.id,
guildId: guild.id,
timeoutId: commandId,
},
},
update: {},
create: {
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
timeoutId: commandId,
cooldown,
},
});
logger.silly(createCooldown);
};
// Button cooldown
export const button = async (i: ButtonInteraction, cooldown: number) => {
const { guild, user, customId } = i;
if (!guild) throw new Error("Guild not found");
// Check if user has a timeout
const hasTimeout = await prisma.cooldown.findUnique({
where: {
guildId_userId_timeoutId: {
guildId: guild.id,
userId: user.id,
timeoutId: customId,
},
},
});
logger.silly(hasTimeout);
// If user is not on timeout
if (hasTimeout) {
const { userId, timeoutId, createdAt } = hasTimeout;
const overDue = 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
const deleteCooldown = await prisma.cooldown.delete({
where: {
guildId_userId_timeoutId: {
guildId: guild.id,
userId: user.id,
timeoutId: customId,
},
},
});
logger.silly(deleteCooldown);
logger.debug(
`Timeout document ${timeoutId} has been deleted from user ${userId}.`
);
}
// Create timeout
const createCooldown = await prisma.cooldown.upsert({
where: {
guildId_userId_timeoutId: {
userId: user.id,
guildId: guild.id,
timeoutId: customId,
},
},
update: {},
create: {
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
timeoutId: customId,
cooldown,
},
});
logger.silly(createCooldown);
};
// Message cooldown
export const message = async (msg: Message, cooldown: number, id: string) => {
const { guild, member } = msg;
if (!guild) throw new Error("Guild not found");
if (!member) throw new Error("Member is undefined");
// Check if user has a timeout
const hasTimeout = await prisma.cooldown.findUnique({
where: {
guildId_userId_timeoutId: {
guildId: guild.id,
userId: member.id,
timeoutId: id,
},
},
});
logger.silly(hasTimeout);
// If user is not on timeout
if (hasTimeout) {
const { userId, timeoutId, createdAt } = hasTimeout;
const overDue = addSeconds(cooldown, createdAt) < new Date();
if (!overDue) {
const diff = Math.round(
(new Date(hasTimeout.createdAt).getTime() - new Date().getTime()) / 1000
);
return `User: ${userId} on timeout-id: ${id} with cooldown: ${cooldown} secs with remaining: ${diff} secs.`;
}
// Delete timeout
const deleteCooldown = await prisma.cooldown.delete({
where: {
guildId_userId_timeoutId: {
guildId: guild.id,
userId: member.id,
timeoutId: id,
},
},
});
logger.silly(deleteCooldown);
logger.debug(
`Timeout document ${timeoutId} has been deleted from user ${userId}.`
);
}
// Create timeout
const createCooldown = await prisma.cooldown.upsert({
where: {
guildId_userId_timeoutId: {
userId: member.id,
guildId: guild.id,
timeoutId: id,
},
},
update: {},
create: {
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
user: {
connectOrCreate: {
create: {
id: member.id,
},
where: {
id: member.id,
},
},
},
timeoutId: id,
cooldown,
},
});
logger.silly(createCooldown);
};

View file

@ -1,3 +1,20 @@
import { PrismaClient } from '@prisma/client'
import { PrismaClient } from "@prisma/client";
import logger from "../../middlewares/logger";
export default new PrismaClient()
const prisma = new PrismaClient();
prisma.$use(async (params, next) => {
const before = Date.now();
const result = await next(params);
const after = Date.now();
logger.debug(
`Query ${params.model}.${params.action} took ${after - before}ms`
);
return result;
});
export default prisma;

View file

@ -1,38 +1,39 @@
import { RESTPostAPIApplicationCommandsJSONBody } from "discord-api-types/v10";
import { Client } from "discord.js";
import { Client, RESTPostAPIApplicationCommandsJSONBody } from "discord.js";
import { ICommand } from "../../interfaces/Command";
import logger from "../../middlewares/logger";
export default async (client: Client) => {
const commandList: Array<RESTPostAPIApplicationCommandsJSONBody> = [];
// 1. Destructure the client.
const { application } = client;
if (!application) throw new Error("No application found");
if (!client.commands) {
throw new Error("client.commands is not defined");
}
// 2. Log that we are starting the command management.
logger.info("🔧 Started command deployment");
logger.info("Gathering command list");
// 3. Get the commands.
const commands: Array<RESTPostAPIApplicationCommandsJSONBody> = [];
client.commands.forEach((command: ICommand) => {
commands.push(command.builder.toJSON());
await Promise.all(
client.commands.map((commandData: ICommand) => {
commandList.push(commandData.builder.toJSON());
logger.verbose(`${commandData.builder.name} pushed to list`);
})
)
.then(() => {
logger.info(`Finished gathering command list.`);
})
.catch((error) => {
throw new Error(`Could not gather command list: ${error}`);
});
await client.application?.commands.set(commandList).then(() => {
logger.info(`Finished updating command list.`);
logger.verbose(`🔧 Loaded command "${command.builder.name}"`);
});
if (process.env.NODE_ENV !== "production") {
await client.application?.commands
.set(commandList, process.env.DISCORD_GUILD_ID)
.then(() => logger.info(`Finished updating guild command list.`));
// 4. Set the commands.
await application.commands.set(commands).then(() => {
logger.info("🔧 Deployed commands globally");
});
// 5. Tell the user that development mode is enabled.
if (process.env.NODE_ENV === "development") {
logger.info("🔧 Development mode enabled");
await application.commands
.set(commands, process.env.DISCORD_GUILD_ID)
.then(() => {
logger.info(`🔧 Deployed commands to guild`);
});
}
// 6. Log that we are done with the command management.
logger.info("🔧 Finished command deployment");
};

View file

@ -1,14 +0,0 @@
import { Client } from "discord.js";
import logger from "../../middlewares/logger";
export default async (client: Client) => {
if (process.env.NODE_ENV !== "production") {
await client?.application?.commands
?.set([], process.env.DISCORD_GUILD_ID)
.then(() => {
return logger.verbose(`Development mode is disabled.`);
});
}
return logger.info(`Development mode is enabled.`);
};

View file

@ -1,96 +1,52 @@
/* eslint-disable no-loops/no-loops */
import { Client } from "discord.js";
import listDir from "../../helpers/checkDirectory";
import checkDirectory from "../../helpers/checkDirectory";
import { IEvent } from "../../interfaces/Event";
import logger from "../../middlewares/logger";
// Registers all available events
// Registers all available events.
export const register = async (client: Client) => {
const eventNames = await listDir("events");
if (!eventNames) throw new Error("📦 No events available");
logger.info("📡 Started event management");
const amountOfEvents = eventNames.length;
let importedEventAmount = 0;
logger.info(`📦 Trying to load ${amountOfEvents} events`);
const eventNames = await checkDirectory("events");
if (!eventNames) return logger.warn("No available events found");
const importEvent = async (eventName: string) => {
// Import event from events
const event: IEvent = await import(`../../events/${eventName}`);
if (!event)
throw new Error(`📦 No event found while importing "${eventName}"`);
if (!event.options)
throw new Error(
`📦 No event options found while importing "${eventName}"`
);
if (!event.execute)
throw new Error(
`📦 No event execute found while importing "${eventName}"`
);
const totalEvents = eventNames.length;
let loadedEvents = 0;
// Register event
logger.info(`📡 Loading ${totalEvents} events`);
// Import an event.
const importEvent = async (name: string) => {
const event: IEvent = await import(`../../events/${name}`);
// Create a new event execute function.
const eventExecutor = async (...args: Promise<void>[]) => {
await event.execute(...args).catch((err) => {
logger.error(`${err}`);
});
await event.execute(...args);
};
if (!event.options?.type)
throw new Error(`📦 No event type found while importing "${eventName}"`);
switch (event.options.type) {
case "once":
client.once(eventName, eventExecutor);
client.once(name, eventExecutor);
break;
case "on":
client.on(eventName, eventExecutor);
client.on(name, eventExecutor);
break;
default:
logger.error(`${eventName} does not have a valid type`);
}
importedEventAmount += 1;
};
// Send log message when it's done loading events
const doneImporting = () => {
if (importedEventAmount !== amountOfEvents) {
return logger.warn(
`📦 Failed importing ${
amountOfEvents - importedEventAmount
} of ${amountOfEvents} events`
);
throw new Error(`📡 Invalid event type for event: ${name}`);
}
return logger.info(`📦 Managed to load all events`);
loadedEvents++;
};
eventNames.forEach(async (eventName: string, index: number) => {
for await (const eventName of eventNames) {
await importEvent(eventName).then(() => {
logger.debug(`📦 Imported the "${eventName}" event`);
logger.verbose(`📡 Loaded event "${eventName}"`);
});
// If done importing
if (index + 1 === amountOfEvents) {
await doneImporting();
if (loadedEvents === totalEvents) {
logger.info("📡 All events loaded");
}
});
// for await (const eventName of eventNames) {
// const event: IEvent = await import(`../../events/${eventName}`);
// const eventExecutor = async (...args: Promise<void>[]) =>
// event.execute(...args).catch(async (err) => {
// logger.error(`${err}`);
// });
// if (!event.options?.type) return;
// switch (event.options.type) {
// case "once":
// client.once(eventName, eventExecutor);
// break;
// case "on":
// client.on(eventName, eventExecutor);
// break;
// }
// }
}
};

View file

@ -9,7 +9,7 @@ export const start = async (client: Client) => {
logger.info("⏰ Started job management");
const jobNames = await checkDirectory("schedules");
if (!jobNames) return logger.warn("No available jobs found");
if (!jobNames) return logger.warn("No available jobs found");
await Promise.all(
jobNames.map(async (jobName) => {

View file

@ -4,17 +4,26 @@ import logger from "../../middlewares/logger";
// Function
export default (client: Client) => {
if (!client?.user) throw new Error("Client's user is undefined.");
const { guilds } = client;
// 1. Destructure the client.
const { guilds, user } = client;
if (!user) throw new Error("No user found");
// 2. Get the total number of guilds and members.
const memberCount = guilds.cache.reduce((a, g) => a + g.memberCount, 0);
const guildCount = guilds.cache.size;
const status = `${memberCount} users in ${guildCount} guilds.`;
client.user.setPresence({
activities: [{ type: ActivityType.Watching, name: status }],
status: "online",
// 3. Set the presence.
user.setPresence({
activities: [
{
name: `${guildCount} guilds | ${memberCount} members`,
type: ActivityType.Watching,
},
],
});
logger.info(`Client's presence is set to "${status}"`);
// 4. Log the presence.
return logger.info(
`👀 Presence set to "${guildCount} guilds | ${memberCount} members"`
);
};

View file

@ -1,4 +0,0 @@
export default (seconds: number, date: Date) => {
date.setSeconds(date.getSeconds() + seconds);
return date;
};

View file

@ -0,0 +1,54 @@
import { Guild, User } from "discord.js";
import prisma from "../../handlers/database";
import transactionRules from "./transactionRules";
export default async (guild: Guild, user: User, amount: number) => {
return await prisma.$transaction(async (tx) => {
// 1. Check if the transaction is valid.
transactionRules(guild, user, amount);
// 2. Make the transaction.
const recipient = await tx.guildMember.upsert({
update: {
creditsEarned: {
increment: amount,
},
},
create: {
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
creditsEarned: amount,
},
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
});
// 3. Verify that the recipient actually is created.
if (!recipient) throw new Error("No recipient available");
// 4. Return the recipient.
return recipient;
});
};

View file

@ -0,0 +1,52 @@
import { Guild, User } from "discord.js";
import prisma from "../../handlers/database";
import transactionRules from "./transactionRules";
export default async (guild: Guild, user: User, amount: number) => {
return await prisma.$transaction(async (tx) => {
// 1. Check if the transaction is valid.
transactionRules(guild, user, amount);
// 2. Make the transaction.
const recipient = await tx.guildMember.upsert({
update: {
creditsEarned: amount,
},
create: {
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
creditsEarned: amount,
},
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
});
// 3. Verify that the recipient actually is created.
if (!recipient) throw new Error("No recipient available");
// 4. Return the recipient.
return recipient;
});
};

View file

@ -0,0 +1,55 @@
import { Guild, User } from "discord.js";
import prisma from "../../handlers/database";
import transactionRules from "./transactionRules";
export default async (guild: Guild, user: User, amount: number) => {
return await prisma.$transaction(async (tx) => {
// 1. Check if the transaction is valid.
transactionRules(guild, user, amount);
// 2. Make the transaction.
const recipient = await tx.guildMember.upsert({
update: {
creditsEarned: {
decrement: amount,
},
},
create: {
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
creditsEarned: -amount,
},
where: {
userId_guildId: {
userId: user.id,
guildId: guild.id,
},
},
});
// 3. Verify that the recipient credits are not below zero.
if (recipient.creditsEarned < -100)
throw new Error("User do not have enough credits");
// 4. Return the recipient.
return recipient;
});
};

View file

@ -0,0 +1,18 @@
import { Guild, User } from "discord.js";
export default (guild: Guild, user: User, amount: number) => {
// 1. Verify that the amount is not above 100.000.000 credits.
if (amount > 100000000) {
throw new Error("You can't give more than 1.000.000 credits.");
}
// 2. Verify that the amount is not below 1 credits.
if (amount <= 0) {
throw new Error("You can't give below one credit.");
}
// 3. Verify that the user is not an bot.
if (user.bot) {
throw new Error("You can't give to an bot.");
}
};

View file

@ -1,13 +1,8 @@
import { Guild, User } from "discord.js";
import prisma from "../../handlers/database";
import transactionRules from "./transactionRules";
// Start an transaction between two users in a guild.
export const transfer = async (
guild: Guild,
from: User,
to: User,
amount: number
) => {
export default async (guild: Guild, from: User, to: User, amount: number) => {
return await prisma.$transaction(async (tx) => {
// 1. Decrement amount from the sender.
const sender = await tx.guildMember.upsert({
@ -47,34 +42,19 @@ export const transfer = async (
},
});
// 2. Verify that the sender actually is created.
if (!sender) throw new Error("No sender available");
// 3. Verify that the sender's balance exists.
if (!sender.creditsEarned) throw new Error("No credits available");
// 4. Verify that the sender's balance didn't go below zero.
if (sender.creditsEarned < 0) {
throw new Error(`${from} doesn't have enough to send ${amount}`);
}
// 5. Verify that the sender is not trying to send less that one credits.
if (amount <= 0) {
throw new Error("You can't transfer below one credit.");
}
// 5. Check if the transactions is valid.
transactionRules(guild, from, amount);
transactionRules(guild, to, amount);
// 6. Verify that the sender is not trying to send more than 100.000.000 credits.
if (amount > 100000000) {
throw new Error("You can't transfer more than 100.000.000 credits.");
}
// 7. Verify that recipient are not an bot.
if (to.bot) throw new Error("You can't transfer to an bot.");
// 8. Verify that sender and recipient are not the same user.
// 6. Verify that sender and recipient are not the same user.
if (from.id === to.id) throw new Error("You can't transfer to yourself.");
// 9. Increment the recipient's balance by amount.
// 7. Increment the recipient's balance by amount.
const recipient = await tx.guildMember.upsert({
update: {
creditsEarned: {

View file

@ -1,9 +1,9 @@
import { Client, Collection, GatewayIntentBits } from "discord.js"; // discord.js
import "dotenv/config";
import { register as commandRegister } from "./handlers/command";
import { register as eventRegister } from "./handlers/event";
import { start as scheduleStart } from "./handlers/schedule";
// Main process that starts all other sub processes
const main = async () => {
// Initiate client object

View file

@ -0,0 +1,95 @@
import { add, formatDuration, intervalToDuration, isPast } from "date-fns";
import { Guild, User } from "discord.js";
import prisma from "../../handlers/database";
import logger from "../logger";
export default async (
guild: Guild,
user: User,
id: string,
cooldown: number,
silent?: boolean
) => {
// Check if user has a timeout
const isOnCooldown = await prisma.cooldown.findUnique({
where: {
guildId_userId_timeoutId: {
guildId: guild.id,
userId: user.id,
timeoutId: id,
},
},
});
logger.silly(isOnCooldown);
if (isOnCooldown) {
const { userId, timeoutId, createdAt } = isOnCooldown;
const dueDate = add(createdAt, { seconds: cooldown });
const duration = formatDuration(
intervalToDuration({
start: new Date(),
end: dueDate,
})
);
if (isPast(dueDate)) {
return await prisma.cooldown.delete({
where: {
guildId_userId_timeoutId: {
guildId: guild.id,
userId: user.id,
timeoutId: id,
},
},
});
}
if (silent) {
return logger.verbose(
`User ${userId} is on cooldown for ${timeoutId}, it ends in ${duration}.`
);
}
throw new Error(`You are still on cooldown for ${duration}`);
}
const createCooldown = await prisma.cooldown.upsert({
where: {
guildId_userId_timeoutId: {
userId: user.id,
guildId: guild.id,
timeoutId: id,
},
},
update: {},
create: {
guild: {
connectOrCreate: {
create: {
id: guild.id,
},
where: {
id: guild.id,
},
},
},
user: {
connectOrCreate: {
create: {
id: user.id,
},
where: {
id: user.id,
},
},
},
timeoutId: id,
cooldown,
},
});
logger.silly(createCooldown);
return createCooldown;
};

View file

@ -0,0 +1,43 @@
/* eslint-disable no-loops/no-loops */
import { add, formatDuration, intervalToDuration, isPast } from "date-fns";
import prisma from "../../handlers/database";
import logger from "../../middlewares/logger";
export const options = {
schedule: "*/30 * * * *", // https://crontab.guru/
};
// Execute the job
export const execute = async () => {
const cooldownsObj = await prisma.cooldown.findMany();
for await (const cooldownObj of cooldownsObj) {
const { guildId, userId, timeoutId, cooldown, createdAt } = cooldownObj;
const dueDate = add(createdAt, { seconds: cooldown });
if (!isPast(dueDate)) return;
const duration = formatDuration(
intervalToDuration({
start: new Date(),
end: dueDate,
})
);
const deleteCooldown = await prisma.cooldown.delete({
where: {
guildId_userId_timeoutId: {
guildId,
userId,
timeoutId,
},
},
});
logger.silly(deleteCooldown);
logger.verbose(
`User ${userId} is on cooldown for ${timeoutId}, it ends in ${duration}.`
);
}
};

View file

@ -1,40 +0,0 @@
/* eslint-disable no-loops/no-loops */
import logger from "../../middlewares/logger";
import addSeconds from "../../helpers/addSeconds";
import prisma from "../../handlers/database";
export const options = {
schedule: "*/30 * * * *", // https://crontab.guru/
};
// Execute the job
export const execute = async () => {
const getCooldown = await prisma.cooldown.findMany();
for await (const timeout of getCooldown) {
const { guildId, userId, timeoutId, cooldown, createdAt } = timeout;
const overDue = addSeconds(cooldown, createdAt) < new Date();
if (overDue) {
logger.info(timeout);
const deleteCooldown = await prisma.cooldown.delete({
where: {
guildId_userId_timeoutId: {
guildId,
userId,
timeoutId,
},
},
});
logger.silly(deleteCooldown);
logger.debug(
`Timeout document ${timeoutId} has been deleted from user ${userId}.`
);
}
}
};