diff --git a/src/commands/admin/cleanup.ts b/src/commands/admin/cleanup.ts new file mode 100644 index 0000000..0980e76 --- /dev/null +++ b/src/commands/admin/cleanup.ts @@ -0,0 +1,45 @@ +import { createCommand } from "@lib/utils"; +import { SlashCommandBuilder, PermissionFlagsBits } from "discord.js"; +import { lootdropService } from "@/modules/economy/lootdrop.service"; +import { createBaseEmbed } from "@lib/embeds"; + +export const cleanup = createCommand({ + data: new SlashCommandBuilder() + .setName("cleanup") + .setDescription("Manually trigger cleanup tasks") + .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) + .addStringOption(option => + option.setName("type") + .setDescription("The type of cleanup to perform") + .setRequired(true) + .addChoices( + { name: 'Lootdrops', value: 'lootdrops' } + ) + ) + .addBooleanOption(option => + option.setName("include_claimed") + .setDescription("Whether to cleanup claimed lootdrops as well (only for lootdrops type)") + .setRequired(false) + ), + execute: async (interaction) => { + await interaction.deferReply({ ephemeral: true }); + + const type = interaction.options.getString("type", true); + const includeClaimed = interaction.options.getBoolean("include_claimed") || false; + + try { + let count = 0; + if (type === 'lootdrops') { + count = await lootdropService.cleanupExpiredLootdrops(includeClaimed); + } + + const embed = createBaseEmbed("Cleanup Complete") + .setDescription(`Successfully executed cleanup for **${type}**.\nDeleted **${count}** records. ${includeClaimed ? "\n(Included claimed items)" : ""}`); + + await interaction.editReply({ embeds: [embed] }); + } catch (error) { + console.error("Cleanup failed:", error); + await interaction.editReply({ content: "❌ An error occurred while performing cleanup." }); + } + } +}); diff --git a/src/modules/economy/lootdrop.service.ts b/src/modules/economy/lootdrop.service.ts index 3b4436e..280710d 100644 --- a/src/modules/economy/lootdrop.service.ts +++ b/src/modules/economy/lootdrop.service.ts @@ -27,7 +27,7 @@ class LootdropService { // Cleanup interval for activity tracking and expired lootdrops setInterval(() => { this.cleanupActivity(); - this.cleanupExpiredLootdrops(); + this.cleanupExpiredLootdrops(true); }, 60000); } @@ -45,16 +45,24 @@ class LootdropService { } } - private async cleanupExpiredLootdrops() { + public async cleanupExpiredLootdrops(includeClaimed: boolean = false): Promise { try { const now = new Date(); - await DrizzleClient.delete(lootdrops) - .where(and( - isNull(lootdrops.claimedBy), - lt(lootdrops.expiresAt, now) - )); + const whereClause = includeClaimed + ? lt(lootdrops.expiresAt, now) + : and(isNull(lootdrops.claimedBy), lt(lootdrops.expiresAt, now)); + + const result = await DrizzleClient.delete(lootdrops) + .where(whereClause) + .returning(); + + if (result.length > 0) { + console.log(`[LootdropService] Cleaned up ${result.length} expired lootdrops.`); + } + return result.length; } catch (error) { console.error("Failed to cleanup lootdrops:", error); + return 0; } }