From 0d02981330866dbe416abeef2a6973ede3e6ba17 Mon Sep 17 00:00:00 2001 From: rainydevzz Date: Wed, 26 Mar 2025 15:21:40 -0700 Subject: [PATCH] super cool refactor --- biome.json | 8 + src/commands/colonThree.ts | 457 ++++++++++-------- src/commands/greets.ts | 103 ++++ src/commands/intro-setup.ts | 38 ++ src/commands/ticket.ts | 65 +-- src/commands/uptime.ts | 40 +- src/components/ticket.ts | 118 ++--- src/db/index.ts | 4 +- .../migrations/0002_colorful_colleen_wing.sql | 11 + .../migrations/0003_clumsy_mephistopheles.sql | 10 + src/db/migrations/meta/0000_snapshot.json | 82 ++-- src/db/migrations/meta/0001_snapshot.json | 144 +++--- src/db/migrations/meta/0002_snapshot.json | 135 ++++++ src/db/migrations/meta/0003_snapshot.json | 190 ++++++++ src/db/migrations/meta/_journal.json | 52 +- src/db/schema.ts | 39 +- src/events/members.ts | 46 +- src/events/messages.ts | 20 +- src/events/ready.ts | 6 +- src/index.ts | 4 +- src/utils/intro-check.ts | 22 + src/utils/uptime-loop.ts | 17 +- 22 files changed, 1140 insertions(+), 471 deletions(-) create mode 100644 biome.json create mode 100644 src/commands/greets.ts create mode 100644 src/commands/intro-setup.ts create mode 100644 src/db/migrations/0002_colorful_colleen_wing.sql create mode 100644 src/db/migrations/0003_clumsy_mephistopheles.sql create mode 100644 src/db/migrations/meta/0002_snapshot.json create mode 100644 src/db/migrations/meta/0003_snapshot.json create mode 100644 src/utils/intro-check.ts diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..9415377 --- /dev/null +++ b/biome.json @@ -0,0 +1,8 @@ +{ + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", + "javascript": { + "parser": { + "unsafeParameterDecoratorsEnabled": true + } + } +} \ No newline at end of file diff --git a/src/commands/colonThree.ts b/src/commands/colonThree.ts index 3349b07..6958b17 100644 --- a/src/commands/colonThree.ts +++ b/src/commands/colonThree.ts @@ -1,241 +1,284 @@ import { Discord, Slash, SlashGroup, SlashOption } from "discordx"; -import { ApplicationCommandOptionType, CommandInteraction, EmbedBuilder, GuildMember, MessageFlags } from "discord.js"; +import { + ApplicationCommandOptionType, + CommandInteraction, + EmbedBuilder, + GuildMember, + MessageFlags, +} from "discord.js"; import db from "../db"; -import { colonTable, type ColonThreeType } from "../db/schema"; +import { colonTable } from "../db/schema"; import { eq, desc } from "drizzle-orm"; @Discord() export class ColonThreeInit { - @Slash({ description: "Init all users for :3 Leaderboard", name: "init_colonthree" }) + @Slash({ + description: "Init all users for :3 Leaderboard", + name: "init_colonthree", + }) async init_colon(inter: CommandInteraction) { - if (Bun.env.OWNER != inter.user.id) { - await inter.reply({ content: "You're not allowed to run this.", flags: MessageFlags.Ephemeral }) - return; - } + if (Bun.env.OWNER != inter.user.id) { + await inter.reply({ + content: "You're not allowed to run this.", + flags: MessageFlags.Ephemeral, + }); + return; + } - for (const userObject of await inter.guild!.members.cache) { - const user = userObject[1]; - if (user.user.bot) { - continue; - } + for (const userObject of await inter.guild!.members.cache) { + const user = userObject[1]; + if (user.user.bot) { + continue; + } - const check = await db.select().from(colonTable).where(eq(colonTable.user, user.id)); + const check = await db + .select() + .from(colonTable) + .where(eq(colonTable.user, user.id)); - if (check.length >= 1) { - continue; - } + if (check.length >= 1) { + continue; + } - await db.insert(colonTable).values({ - user: user.id, - amount: 0, - messages_count: 0 - }); - } + await db.insert(colonTable).values({ + user: user.id, + amount: 0, + messages_count: 0, + }); + } - await inter.reply({ content: "All users have been initalized", flags: MessageFlags.Ephemeral }); + await inter.reply({ + content: "All users have been initalized", + flags: MessageFlags.Ephemeral, + }); } } @Discord() @SlashGroup({ - description: "The :3 Commands", - name: "colonthree" + description: "The :3 Commands", + name: "colonthree", }) @SlashGroup("colonthree") export class ColonThree { - @Slash({ description: "Stats" }) - async stats( - @SlashOption({ - description: "Get stats from user", - name: "user", - required: false, - type: ApplicationCommandOptionType.User, - }) - user: GuildMember, - inter: CommandInteraction - ) { - const statsUser = ( - await db - .select() - .from(colonTable) - .where(eq(colonTable.user, (user?.id || inter.user.id))) - )[0]; + @Slash({ description: "Stats" }) + async stats( + @SlashOption({ + description: "Get stats from user", + name: "user", + required: false, + type: ApplicationCommandOptionType.User, + }) + user: GuildMember, + inter: CommandInteraction, + ) { + const statsUser = ( + await db + .select() + .from(colonTable) + .where(eq(colonTable.user, user?.id || inter.user.id)) + )[0]; - if (!statsUser) { - await inter.reply({ content: `Failed to get <@${user?.id || inter.user.id}>'s stats.`, flags: MessageFlags.Ephemeral }); - return; - } + if (!statsUser) { + await inter.reply({ + content: `Failed to get <@${user?.id || inter.user.id}>'s stats.`, + flags: MessageFlags.Ephemeral, + }); + return; + } - const userObject = inter.client.users.cache.get(statsUser.user); - if (!userObject) { - await inter.reply({ content: "Something went wrong...", flags: MessageFlags.Ephemeral }); - return; - } + const userObject = inter.client.users.cache.get(statsUser.user); + if (!userObject) { + await inter.reply({ + content: "Something went wrong...", + flags: MessageFlags.Ephemeral, + }); + return; + } - const embed = new EmbedBuilder() - .setTitle(`${userObject.username}'s Stats`) - .setAuthor({ name: userObject.username, iconURL: userObject.avatarURL()! }) - .addFields( - { - name: '**Total :3 Sent**', - value: `► **${statsUser.amount}** times`, - inline: true - }, - { - name: '**Average :3 per Message**', - value: `► **${(statsUser.amount / statsUser.messages_count).toFixed(2)}**`, - inline: true - }, - { - name: '**Messages Count**', - value: `► **${statsUser.messages_count}**`, - inline: true - } - ); - - await inter.reply( { embeds: [embed], flags: MessageFlags.Ephemeral }); - } + const embed = new EmbedBuilder() + .setTitle(`${userObject.username}'s Stats`) + .setAuthor({ + name: userObject.username, + iconURL: userObject.avatarURL()!, + }) + .addFields( + { + name: "**Total :3 Sent**", + value: `► **${statsUser.amount}** times`, + inline: true, + }, + { + name: "**Average :3 per Message**", + value: `► **${(statsUser.amount / statsUser.messages_count).toFixed(2)}**`, + inline: true, + }, + { + name: "**Messages Count**", + value: `► **${statsUser.messages_count}**`, + inline: true, + }, + ); - @Slash({ description: "Compare" }) - async compare( - @SlashOption({ - description: "Get stats from user", - name: "x", - required: true, - type: ApplicationCommandOptionType.User, - }) - x: GuildMember, - @SlashOption({ - description: "Get stats from user", - name: "y", - required: true, - type: ApplicationCommandOptionType.User, - }) - y: GuildMember, - inter: CommandInteraction - ) { - const xStats = ( - await db - .select() - .from(colonTable) - .where(eq(colonTable.user, x.id)) - )[0]; - - if (!xStats) { - await inter.reply({ content: `Failed to get <@${x.id}>'s stats.`, flags: MessageFlags.Ephemeral }); - return; - } - - const yStats = ( - await db - .select() - .from(colonTable) - .where(eq(colonTable.user, y.id)) - )[0]; - - if (!yStats) { - await inter.reply({ content: `Failed to get <@${y.id}>'s stats.`, flags: MessageFlags.Ephemeral }); - return; - } - - const winner = xStats.amount > yStats.amount ? x : y; - - const embed = new EmbedBuilder() - .setTitle(`🎉 ${winner.user.username} is using :3 more!`) - .addFields( - { - name: `📊 ${x.user.username}'s Stats`, - value: `► Sent **${xStats.amount}** :3\n► Avg: **${(xStats.amount / xStats.messages_count).toFixed(2)}** :3 per message`, - inline: true - }, - { - name: `📊 ${y.user.username}'s Stats`, - value: `► Sent **${yStats.amount}** :3\n► Avg: **${(yStats.amount / yStats.messages_count).toFixed(2)}** :3 per message`, - inline: true - } - ) - - await inter.reply({ embeds: [embed] }); - } - - @Slash({ description: "Leaderboard" }) - async board(inter: CommandInteraction) { - const theColonThreeLeaders = await db.select() - .from(colonTable) - .orderBy(desc(colonTable.amount)); - - const topTen = theColonThreeLeaders - .slice(0, 10) - .filter(user => user.amount >= 1); - - const leaderboardText = topTen.map((user, index) => { - const rank = index + 1; - const avg = (user.amount / user.messages_count).toFixed(2); - - const medal = rank === 1 ? "🥇" : rank === 2 ? "🥈" : rank === 3 ? "🥉" : `**${rank}.**`; - - return `${medal} <@${user.user}> » **${user.amount}** :3 (avg: **${avg}**)`; - }); - - const embed = new EmbedBuilder() - .setTitle(`🏆 :3 Leaderboard`) - .setDescription(leaderboardText.join("\n") || "*No data yet!*") - .addFields({ - name: 'Stats', - value: `► **Tracking users:** ${theColonThreeLeaders.length}`, - inline: false - }) - .setFooter({ text: 'Keep using :3!!!!!!' }) - .setTimestamp(); - - await inter.reply({ embeds: [embed] }); + await inter.reply({ embeds: [embed], flags: MessageFlags.Ephemeral }); } - @Slash({ description: "Stop tracking and delete my data" }) + @Slash({ description: "Compare" }) + async compare( + @SlashOption({ + description: "Get stats from user", + name: "x", + required: true, + type: ApplicationCommandOptionType.User, + }) + x: GuildMember, + @SlashOption({ + description: "Get stats from user", + name: "y", + required: true, + type: ApplicationCommandOptionType.User, + }) + y: GuildMember, + inter: CommandInteraction, + ) { + const xStats = ( + await db.select().from(colonTable).where(eq(colonTable.user, x.id)) + )[0]; + + if (!xStats) { + await inter.reply({ + content: `Failed to get <@${x.id}>'s stats.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const yStats = ( + await db.select().from(colonTable).where(eq(colonTable.user, y.id)) + )[0]; + + if (!yStats) { + await inter.reply({ + content: `Failed to get <@${y.id}>'s stats.`, + flags: MessageFlags.Ephemeral, + }); + return; + } + + const winner = xStats.amount > yStats.amount ? x : y; + + const embed = new EmbedBuilder() + .setTitle(`🎉 ${winner.user.username} is using :3 more!`) + .addFields( + { + name: `📊 ${x.user.username}'s Stats`, + value: `► Sent **${xStats.amount}** :3\n► Avg: **${(xStats.amount / xStats.messages_count).toFixed(2)}** :3 per message`, + inline: true, + }, + { + name: `📊 ${y.user.username}'s Stats`, + value: `► Sent **${yStats.amount}** :3\n► Avg: **${(yStats.amount / yStats.messages_count).toFixed(2)}** :3 per message`, + inline: true, + }, + ); + + await inter.reply({ embeds: [embed] }); + } + + @Slash({ description: "Leaderboard" }) + async board(inter: CommandInteraction) { + const theColonThreeLeaders = await db + .select() + .from(colonTable) + .orderBy(desc(colonTable.amount)); + + const topTen = theColonThreeLeaders + .slice(0, 10) + .filter((user) => user.amount >= 1); + + const leaderboardText = topTen.map((user, index) => { + const rank = index + 1; + const avg = (user.amount / user.messages_count).toFixed(2); + + const medal = + rank === 1 + ? "🥇" + : rank === 2 + ? "🥈" + : rank === 3 + ? "🥉" + : `**${rank}.**`; + + return `${medal} <@${user.user}> » **${user.amount}** :3 (avg: **${avg}**)`; + }); + + const embed = new EmbedBuilder() + .setTitle(`🏆 :3 Leaderboard`) + .setDescription(leaderboardText.join("\n") || "*No data yet!*") + .addFields({ + name: "Stats", + value: `► **Tracking users:** ${theColonThreeLeaders.length}`, + inline: false, + }) + .setFooter({ text: "Keep using :3!!!!!!" }) + .setTimestamp(); + + await inter.reply({ embeds: [embed] }); + } + + @Slash({ description: "Stop tracking and delete my data" }) async delete( - @SlashOption({ - description: "Type confirm to delete", - name: "confirmation", - required: true, - type: ApplicationCommandOptionType.String, - }) - confirmation: string, - inter: CommandInteraction - ) { - if (confirmation === "confirm") { - await db.delete(colonTable).where(eq(colonTable.user, inter.user.id)); - await inter.reply({ content: "All of data was deleted, you will not be tracked again.", flags: MessageFlags.Ephemeral }); - return; - } + @SlashOption({ + description: "Type confirm to delete", + name: "confirmation", + required: true, + type: ApplicationCommandOptionType.String, + }) + confirmation: string, + inter: CommandInteraction, + ) { + if (confirmation === "confirm") { + await db.delete(colonTable).where(eq(colonTable.user, inter.user.id)); + await inter.reply({ + content: "All of data was deleted, you will not be tracked again.", + flags: MessageFlags.Ephemeral, + }); + return; + } - await inter.reply({ content: 'You need to type "confirm" to delete.', flags: MessageFlags.Ephemeral }); - } + await inter.reply({ + content: 'You need to type "confirm" to delete.', + flags: MessageFlags.Ephemeral, + }); + } - @Slash({ description: "Start tracking" }) - async start( - inter: CommandInteraction - ) { - const check = ( - await db - .select() - .from(colonTable) - .where(eq(colonTable.user, inter.user.id) - ) - )[0]; + @Slash({ description: "Start tracking" }) + async start(inter: CommandInteraction) { + const check = ( + await db + .select() + .from(colonTable) + .where(eq(colonTable.user, inter.user.id)) + )[0]; - if (check) { - await inter.reply({ content: "Scythe already tracks your :3 data.", flags: MessageFlags.Ephemeral }); - return; - } + if (check) { + await inter.reply({ + content: "Scythe already tracks your :3 data.", + flags: MessageFlags.Ephemeral, + }); + return; + } - await db.insert(colonTable).values({ - user: inter.user.id, - amount: 0, - messages_count: 0 - }); - await inter.reply({ content: "Scythe starts tracking your :3 data again.", flags: MessageFlags.Ephemeral }); - } + await db.insert(colonTable).values({ + user: inter.user.id, + amount: 0, + messages_count: 0, + }); + await inter.reply({ + content: "Scythe starts tracking your :3 data again.", + flags: MessageFlags.Ephemeral, + }); + } } - diff --git a/src/commands/greets.ts b/src/commands/greets.ts new file mode 100644 index 0000000..735c5c1 --- /dev/null +++ b/src/commands/greets.ts @@ -0,0 +1,103 @@ +import { + ApplicationCommandOptionType, + MessageFlags, + TextChannel, + type CommandInteraction, +} from "discord.js"; +import { Discord, Slash, SlashOption } from "discordx"; +import db from "../db"; +import { byeTable, greetsTable } from "../db/schema"; +import { sql } from "drizzle-orm"; + +@Discord() +export class GreetCmds { + @Slash({ name: "hello-setup", description: "set up the hello message :3" }) + async helloSetup( + @SlashOption({ + name: "channel", + description: "channel to send in", + required: true, + type: ApplicationCommandOptionType.Channel, + }) + channel: TextChannel, + @SlashOption({ + name: "message", + description: "message to send", + required: true, + type: ApplicationCommandOptionType.String, + }) + message: string, + inter: CommandInteraction, + ) { + if (inter.user.id != inter.guild?.ownerId) { + return await inter.reply({ + content: "you cannot use this command u goober!", + flags: MessageFlags.Ephemeral, + }); + } + if (!inter.guildId) { + return await inter.reply("you can't use this in DMs silly!"); + } + await db + .insert(greetsTable) + .values({ + guild: inter.guildId, + channel: channel.id, + message, + }) + .onConflictDoUpdate({ + target: greetsTable.guild, + set: { message, channel: channel.id }, + setWhere: sql`guild = ${inter.guildId}`, + }); + await inter.reply({ + content: "setup done! :3", + flags: MessageFlags.Ephemeral, + }); + } + + @Slash({ name: "bye-setup", description: "set up the bye message :3" }) + async byeSetup( + @SlashOption({ + name: "channel", + description: "channel to send in", + required: true, + type: ApplicationCommandOptionType.Channel, + }) + channel: TextChannel, + @SlashOption({ + name: "message", + description: "message to send", + required: true, + type: ApplicationCommandOptionType.String, + }) + message: string, + inter: CommandInteraction, + ) { + if (inter.user.id != inter.guild?.ownerId) { + return await inter.reply({ + content: "you cannot use this command u goober!", + flags: MessageFlags.Ephemeral, + }); + } + if (!inter.guildId) { + return await inter.reply("you can't use this in DMs silly!"); + } + await db + .insert(byeTable) + .values({ + guild: inter.guildId, + channel: channel.id, + message, + }) + .onConflictDoUpdate({ + target: byeTable.guild, + set: { message, channel: channel.id }, + setWhere: sql`guild = ${inter.guildId}`, + }); + await inter.reply({ + content: "setup done! :3", + flags: MessageFlags.Ephemeral, + }); + } +} diff --git a/src/commands/intro-setup.ts b/src/commands/intro-setup.ts new file mode 100644 index 0000000..9ae24a5 --- /dev/null +++ b/src/commands/intro-setup.ts @@ -0,0 +1,38 @@ +import { + ApplicationCommandOptionType, + CommandInteraction, + MessageFlags, + type TextChannel, +} from "discord.js"; +import { Discord, Slash, SlashOption } from "discordx"; +import db from "../db"; +import { introTable } from "../db/schema"; +import { sql } from "drizzle-orm"; + +@Discord() +export class Intro { + @Slash({ name: "intro-purge", description: "sets up intro purge" }) + async introPurge( + @SlashOption({ + name: "channel", + description: "channel to check", + required: true, + type: ApplicationCommandOptionType.Channel, + }) + channel: TextChannel, + inter: CommandInteraction, + ) { + await db + .insert(introTable) + .values({ + guild: inter.guildId!, + channel: channel.id, + }) + .onConflictDoUpdate({ + target: introTable.guild, + set: { channel: channel.id }, + setWhere: sql`guild = ${inter.guildId}`, + }); + await inter.reply({content: "intro setup done!", flags: MessageFlags.Ephemeral}); + } +} diff --git a/src/commands/ticket.ts b/src/commands/ticket.ts index c43b9b2..bf4cc4e 100644 --- a/src/commands/ticket.ts +++ b/src/commands/ticket.ts @@ -1,37 +1,48 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, Message, MessageFlags, type CommandInteraction, type TextChannel } from "discord.js"; +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + EmbedBuilder, + MessageFlags, + type CommandInteraction, + type TextChannel, +} from "discord.js"; import { Discord, Slash } from "discordx"; @Discord() export class TicketCmd { - @Slash({ name: "setup-ticket", description: "Setup the tickets" }) - async snipe(inter: CommandInteraction) { - if (inter.user.id != Bun.env.OWNER) { - await inter.reply({ content: "You're not the owner", flags: MessageFlags.Ephemeral }); - return; - } + @Slash({ name: "setup-ticket", description: "Setup the tickets" }) + async snipe(inter: CommandInteraction) { + if (inter.user.id != Bun.env.OWNER) { + await inter.reply({ + content: "You're not the owner", + flags: MessageFlags.Ephemeral, + }); + return; + } - const channel = inter.client.channels.cache.get(Bun.env.TICKET_CHANNEL) as TextChannel; + const channel = inter.client.channels.cache.get( + Bun.env.TICKET_CHANNEL, + ) as TextChannel; - const embed = new EmbedBuilder() - .setTitle(`Tickets`) - .setDescription( - `Click the button to make a ticket! :3`, - ); - - const createButton = new ButtonBuilder() - .setCustomId('createTicket') - .setLabel('Create Ticket') + const embed = new EmbedBuilder() + .setTitle(`Tickets`) + .setDescription(`Click the button to make a ticket! :3`); + + const createButton = new ButtonBuilder() + .setCustomId("createTicket") + .setLabel("Create Ticket") .setStyle(ButtonStyle.Primary); - - - const row = new ActionRowBuilder() - .addComponents(createButton); - await channel.send({ - embeds: [embed], - components: [row] - }); + const row = new ActionRowBuilder().addComponents( + createButton, + ); - await inter.reply({ content: "Done", flags: MessageFlags.Ephemeral }); - } + await channel.send({ + embeds: [embed], + components: [row], + }); + + await inter.reply({ content: "Done", flags: MessageFlags.Ephemeral }); + } } diff --git a/src/commands/uptime.ts b/src/commands/uptime.ts index 0c1b342..9f0f738 100644 --- a/src/commands/uptime.ts +++ b/src/commands/uptime.ts @@ -1,19 +1,37 @@ -import type { CommandInteraction, TextChannel } from "discord.js"; -import { Discord, Slash } from "discordx"; +import { + ApplicationCommandOptionType, + type CommandInteraction, + type TextChannel, +} from "discord.js"; +import { Discord, Slash, SlashOption } from "discordx"; +import db from "../db"; +import { uptimeTable } from "../db/schema"; @Discord() export class UptimeCmd { @Slash({ name: "uptime-setup", description: "set up uptime cmd" }) - async uptimeCmd(inter: CommandInteraction) { - if (inter.user.id != Bun.env.OWNER) { - await inter.reply("you cannot run this command :p"); - return; + async uptimeCmd( + @SlashOption({ + name: "channel", + description: "channel to send in", + required: true, + type: ApplicationCommandOptionType.Channel, + }) + channel: TextChannel, + inter: CommandInteraction, + ) { + if (inter.user.id != inter.guild?.ownerId) { + return await inter.reply("you cannot run this command :p"); } - const channel = inter.client.channels.cache.get( - Bun.env.SCYTHE_CHANNEL, - ) as TextChannel; - await channel.send( - `bot is up, last ping: | if the ping was more than 1 minute ago, cosmic needs to check the bot lol :3`, + + const msg = await channel.send( + `bot is up, last ping: | if the ping was more than 1 minute ago, cosmic needs to check the bot lol :3`, ); + + await db.insert(uptimeTable).values({ + guild: inter.guildId!, + channel: channel.id, + message: msg.id, + }); } } diff --git a/src/components/ticket.ts b/src/components/ticket.ts index 2e570d2..17fe063 100644 --- a/src/components/ticket.ts +++ b/src/components/ticket.ts @@ -1,13 +1,13 @@ -import { - ActionRowBuilder, - ButtonBuilder, - ButtonInteraction, - ButtonStyle, - CategoryChannel, - ChannelType, - EmbedBuilder, - MessageFlags, - PermissionsBitField +import { + ActionRowBuilder, + ButtonBuilder, + ButtonInteraction, + ButtonStyle, + CategoryChannel, + ChannelType, + EmbedBuilder, + MessageFlags, + PermissionsBitField, } from "discord.js"; import { ButtonComponent, Discord } from "discordx"; @@ -20,14 +20,17 @@ import { eq } from "drizzle-orm"; export class TicketComponenets { @ButtonComponent({ id: "createTicket" }) async createHandler(inter: ButtonInteraction): Promise { - const check = await db.select().from(ticketsTable).where(eq(ticketsTable.user, inter.user.id)); - if (check.length >= 1) { - await inter.reply({ - content: "You already have a ticket open.", - flags: MessageFlags.Ephemeral - }); - return; - } + const check = await db + .select() + .from(ticketsTable) + .where(eq(ticketsTable.user, inter.user.id)); + if (check.length >= 1) { + await inter.reply({ + content: "You already have a ticket open.", + flags: MessageFlags.Ephemeral, + }); + return; + } let channel = await inter.guild!.channels.create({ type: ChannelType.GuildText, @@ -39,51 +42,58 @@ export class TicketComponenets { }, { id: inter.user.id, - allow: [PermissionsBitField.Flags.ViewChannel, PermissionsBitField.Flags.SendMessages], + allow: [ + PermissionsBitField.Flags.ViewChannel, + PermissionsBitField.Flags.SendMessages, + ], }, { id: Bun.env.MOD_ROLE, - allow: [PermissionsBitField.Flags.ViewChannel, PermissionsBitField.Flags.SendMessages], - } - ] + allow: [ + PermissionsBitField.Flags.ViewChannel, + PermissionsBitField.Flags.SendMessages, + ], + }, + ], }); - const category = inter.guild?.channels.cache.get(Bun.env.TICKET_CATEGORY) as CategoryChannel; - channel = await channel.setParent(category); + const category = inter.guild?.channels.cache.get( + Bun.env.TICKET_CATEGORY, + ) as CategoryChannel; + channel = await channel.setParent(category); - const embed = new EmbedBuilder() - .setTitle(`Tickets`) - .setDescription( - `<@${inter.user.id}> here's your ticket!`, - ); - - const deleteButton = new ButtonBuilder() - .setCustomId('deleteTicket') - .setLabel('Delete Ticket') - .setStyle(ButtonStyle.Primary); - - const row = new ActionRowBuilder() - .addComponents(deleteButton); + const embed = new EmbedBuilder() + .setTitle(`Tickets`) + .setDescription(`<@${inter.user.id}> here's your ticket!`); + + const deleteButton = new ButtonBuilder() + .setCustomId("deleteTicket") + .setLabel("Delete Ticket") + .setStyle(ButtonStyle.Primary); + + const row = new ActionRowBuilder().addComponents( + deleteButton, + ); await channel.send({ - embeds: [embed], - components: [row] - }); + embeds: [embed], + components: [row], + }); - await inter.reply({ - content: `<#${channel.id}>`, - flags: MessageFlags.Ephemeral - }) - - await db.insert(ticketsTable).values({ - user: inter.user.id, - channel: channel.id - }); + await inter.reply({ + content: `<#${channel.id}>`, + flags: MessageFlags.Ephemeral, + }); + + await db.insert(ticketsTable).values({ + user: inter.user.id, + channel: channel.id, + }); } - @ButtonComponent({ id: "deleteTicket" }) - async deleteHandler(inter: ButtonInteraction): Promise { - await inter.channel?.delete(`<@${inter.user.id}> has deleted the ticket.`); - await db.delete(ticketsTable).where(eq(ticketsTable.user, inter.user.id)); - } + @ButtonComponent({ id: "deleteTicket" }) + async deleteHandler(inter: ButtonInteraction): Promise { + await inter.channel?.delete(`<@${inter.user.id}> has deleted the ticket.`); + await db.delete(ticketsTable).where(eq(ticketsTable.user, inter.user.id)); + } } diff --git a/src/db/index.ts b/src/db/index.ts index 3979363..240b09e 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -1,3 +1,3 @@ -import { drizzle } from 'drizzle-orm/libsql'; +import { drizzle } from "drizzle-orm/libsql"; -export default drizzle(Bun.env.DB); \ No newline at end of file +export default drizzle(Bun.env.DB); diff --git a/src/db/migrations/0002_colorful_colleen_wing.sql b/src/db/migrations/0002_colorful_colleen_wing.sql new file mode 100644 index 0000000..797a7fa --- /dev/null +++ b/src/db/migrations/0002_colorful_colleen_wing.sql @@ -0,0 +1,11 @@ +CREATE TABLE `bye` ( + `guild` text PRIMARY KEY NOT NULL, + `channel` text NOT NULL, + `message` text NOT NULL +); +--> statement-breakpoint +CREATE TABLE `greets` ( + `guild` text PRIMARY KEY NOT NULL, + `channel` text NOT NULL, + `message` text NOT NULL +); diff --git a/src/db/migrations/0003_clumsy_mephistopheles.sql b/src/db/migrations/0003_clumsy_mephistopheles.sql new file mode 100644 index 0000000..541dfbe --- /dev/null +++ b/src/db/migrations/0003_clumsy_mephistopheles.sql @@ -0,0 +1,10 @@ +CREATE TABLE `intro` ( + `guild` text PRIMARY KEY NOT NULL, + `channel` text NOT NULL +); +--> statement-breakpoint +CREATE TABLE `uptime` ( + `guild` text PRIMARY KEY NOT NULL, + `channel` text NOT NULL, + `message` text NOT NULL +); diff --git a/src/db/migrations/meta/0000_snapshot.json b/src/db/migrations/meta/0000_snapshot.json index dbfd012..a866775 100644 --- a/src/db/migrations/meta/0000_snapshot.json +++ b/src/db/migrations/meta/0000_snapshot.json @@ -1,42 +1,42 @@ { - "version": "6", - "dialect": "sqlite", - "id": "fa98c7d2-c794-4f03-887b-f6f5c1b3891d", - "prevId": "00000000-0000-0000-0000-000000000000", - "tables": { - "tickets": { - "name": "tickets", - "columns": { - "user": { - "name": "user", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "channel": { - "name": "channel", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file + "version": "6", + "dialect": "sqlite", + "id": "fa98c7d2-c794-4f03-887b-f6f5c1b3891d", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "tickets": { + "name": "tickets", + "columns": { + "user": { + "name": "user", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/src/db/migrations/meta/0001_snapshot.json b/src/db/migrations/meta/0001_snapshot.json index 4e7b605..e2bf89d 100644 --- a/src/db/migrations/meta/0001_snapshot.json +++ b/src/db/migrations/meta/0001_snapshot.json @@ -1,73 +1,73 @@ { - "version": "6", - "dialect": "sqlite", - "id": "a3e18d09-b7d4-48e3-8920-1fa55c43ee70", - "prevId": "fa98c7d2-c794-4f03-887b-f6f5c1b3891d", - "tables": { - "colonthree": { - "name": "colonthree", - "columns": { - "user": { - "name": "user", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "messages_count": { - "name": "messages_count", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "tickets": { - "name": "tickets", - "columns": { - "user": { - "name": "user", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "channel": { - "name": "channel", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file + "version": "6", + "dialect": "sqlite", + "id": "a3e18d09-b7d4-48e3-8920-1fa55c43ee70", + "prevId": "fa98c7d2-c794-4f03-887b-f6f5c1b3891d", + "tables": { + "colonthree": { + "name": "colonthree", + "columns": { + "user": { + "name": "user", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "amount": { + "name": "amount", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messages_count": { + "name": "messages_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tickets": { + "name": "tickets", + "columns": { + "user": { + "name": "user", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/src/db/migrations/meta/0002_snapshot.json b/src/db/migrations/meta/0002_snapshot.json new file mode 100644 index 0000000..f29bbb7 --- /dev/null +++ b/src/db/migrations/meta/0002_snapshot.json @@ -0,0 +1,135 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "2218a8ed-3583-479c-b142-997455b0c7dc", + "prevId": "a3e18d09-b7d4-48e3-8920-1fa55c43ee70", + "tables": { + "bye": { + "name": "bye", + "columns": { + "guild": { + "name": "guild", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "colonthree": { + "name": "colonthree", + "columns": { + "user": { + "name": "user", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "amount": { + "name": "amount", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messages_count": { + "name": "messages_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "greets": { + "name": "greets", + "columns": { + "guild": { + "name": "guild", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tickets": { + "name": "tickets", + "columns": { + "user": { + "name": "user", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/src/db/migrations/meta/0003_snapshot.json b/src/db/migrations/meta/0003_snapshot.json new file mode 100644 index 0000000..e943b4f --- /dev/null +++ b/src/db/migrations/meta/0003_snapshot.json @@ -0,0 +1,190 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "fb3b9c6d-7d3b-4651-b230-e163bf08b586", + "prevId": "2218a8ed-3583-479c-b142-997455b0c7dc", + "tables": { + "bye": { + "name": "bye", + "columns": { + "guild": { + "name": "guild", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "colonthree": { + "name": "colonthree", + "columns": { + "user": { + "name": "user", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "amount": { + "name": "amount", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messages_count": { + "name": "messages_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "greets": { + "name": "greets", + "columns": { + "guild": { + "name": "guild", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "intro": { + "name": "intro", + "columns": { + "guild": { + "name": "guild", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tickets": { + "name": "tickets", + "columns": { + "user": { + "name": "user", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "uptime": { + "name": "uptime", + "columns": { + "guild": { + "name": "guild", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json index 0e72227..52d4282 100644 --- a/src/db/migrations/meta/_journal.json +++ b/src/db/migrations/meta/_journal.json @@ -1,20 +1,34 @@ { - "version": "7", - "dialect": "sqlite", - "entries": [ - { - "idx": 0, - "version": "6", - "when": 1742570954158, - "tag": "0000_nervous_komodo", - "breakpoints": true - }, - { - "idx": 1, - "version": "6", - "when": 1742844574438, - "tag": "0001_warm_ego", - "breakpoints": true - } - ] -} \ No newline at end of file + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1742570954158, + "tag": "0000_nervous_komodo", + "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1742844574438, + "tag": "0001_warm_ego", + "breakpoints": true + }, + { + "idx": 2, + "version": "6", + "when": 1742864217240, + "tag": "0002_colorful_colleen_wing", + "breakpoints": true + }, + { + "idx": 3, + "version": "6", + "when": 1742927150677, + "tag": "0003_clumsy_mephistopheles", + "breakpoints": true + } + ] +} diff --git a/src/db/schema.ts b/src/db/schema.ts index a6c3532..6018e62 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -3,14 +3,37 @@ import { text, sqliteTable, int } from "drizzle-orm/sqlite-core"; import type { InferSelectModel } from "drizzle-orm"; export const ticketsTable = sqliteTable("tickets", { - user: text().primaryKey().notNull(), - channel: text().notNull() -}) + user: text().primaryKey().notNull(), + channel: text().notNull(), +}); export const colonTable = sqliteTable("colonthree", { - user: text().primaryKey().notNull(), - amount: int().notNull(), - messages_count: int().notNull() -}) + user: text().primaryKey().notNull(), + amount: int().notNull(), + messages_count: int().notNull(), +}); -export type ColonThreeType = InferSelectModel; \ No newline at end of file +export const greetsTable = sqliteTable("greets", { + guild: text().primaryKey().notNull(), + channel: text().notNull(), + message: text().notNull(), +}); + +export const byeTable = sqliteTable("bye", { + guild: text().primaryKey().notNull(), + channel: text().notNull(), + message: text().notNull(), +}); + +export const uptimeTable = sqliteTable("uptime", { + guild: text().primaryKey(), + channel: text().notNull(), + message: text().notNull(), +}); + +export const introTable = sqliteTable("intro", { + guild: text().primaryKey(), + channel: text().notNull(), +}); + +export type ColonThreeType = InferSelectModel; diff --git a/src/events/members.ts b/src/events/members.ts index cd0eb45..b448257 100644 --- a/src/events/members.ts +++ b/src/events/members.ts @@ -2,39 +2,63 @@ import type { TextChannel } from "discord.js"; import { Client, Discord, On, type ArgsOf } from "discordx"; import db from "../db"; -import { colonTable } from "../db/schema"; +import { byeTable, colonTable, greetsTable } from "../db/schema"; import { eq } from "drizzle-orm"; @Discord() export class MemberEvents { @On({ event: "guildMemberAdd" }) async memberAdd([member]: ArgsOf<"guildMemberAdd">, client: Client) { - const channel = client.channels.cache.get(Bun.env.WELCOME!) as TextChannel; - await channel.send( - `Welcome to **${member.guild.name}** <@${member.user.id}> ! You are member #${member.guild.memberCount}! Get a color role and Operating System role(s) in the Channels & Roles section if you want and enjoy your stay <3`, - ); + const greetRes = await db + .select() + .from(greetsTable) + .where(eq(greetsTable.guild, member.guild.id)); + if (greetRes.length > 0) { + const channel = client.channels.cache.get( + greetRes[0].channel, + ) as TextChannel; + await channel.send( + greetRes[0].message.replace("{user}", `<@${member.user.id}>`), + ); + } + if (member.user.bot) { const botRole = member.guild.roles.cache.get(Bun.env.BOT_ROLE!); if (botRole) { await member.roles.add(botRole); } } else { + if(Date.now() - member.user.createdAt.getTime() < 1000 * 60 * 60 * 24 * 7) { + try { + await member.send("to protect against raids, bots, and other disturbances, accounts under a week old are kicked upon joining. please wait for your account to mature before rejoining.") + } catch(_) {} + await member.kick("account less than week old") + return; + } await db.insert(colonTable).values({ user: member.id, amount: 0, - messages_count: 0 + messages_count: 0, }); } } @On({ event: "guildMemberRemove" }) async memberRemove([member]: ArgsOf<"guildMemberRemove">, client: Client) { - const channel = client.channels.cache.get(Bun.env.GOODBYE!) as TextChannel; - await channel.send(`We're sad to see you go, ${member.user.username}.`); + const byeRes = await db + .select() + .from(byeTable) + .where(eq(byeTable.guild, member.guild.id)); + if (byeRes.length > 0) { + const channel = client.channels.cache.get( + byeRes[0].channel, + ) as TextChannel; + await channel.send( + byeRes[0].message.replace("{user}", `${member.user.username}`), + ); + } - await db - .delete(colonTable) - .where(eq(colonTable.user, member.id)); + await db.delete(colonTable).where(eq(colonTable.user, member.id)); } @On({ event: "guildMemberUpdate" }) diff --git a/src/events/messages.ts b/src/events/messages.ts index e97de8f..8deb03c 100644 --- a/src/events/messages.ts +++ b/src/events/messages.ts @@ -46,14 +46,20 @@ export class MessageEvents { if (cThreeRegex.test(msg.content)) { let colonThrees = msg.content.match(cThreeRegex); - await db.update(colonTable).set({ - amount: sql`${colonTable.amount} + ${colonThrees?.length}`, - messages_count: sql`${colonTable.messages_count} + 1`, - }).where(eq(colonTable.user, msg.author.id)); + await db + .update(colonTable) + .set({ + amount: sql`${colonTable.amount} + ${colonThrees?.length}`, + messages_count: sql`${colonTable.messages_count} + 1`, + }) + .where(eq(colonTable.user, msg.author.id)); } else { - await db.update(colonTable).set({ - messages_count: sql`${colonTable.messages_count} + 1`, - }).where(eq(colonTable.user, msg.author.id)); + await db + .update(colonTable) + .set({ + messages_count: sql`${colonTable.messages_count} + 1`, + }) + .where(eq(colonTable.user, msg.author.id)); } } } diff --git a/src/events/ready.ts b/src/events/ready.ts index 19beb6a..2c531ed 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,8 +1,8 @@ import { Client, Discord, On, type ArgsOf } from "discordx"; import { underageCheck } from "../utils/underage"; import { bumpRemind } from "../utils/bump"; -import {stat, mkdir} from "fs/promises"; import { uptimeLoop } from "../utils/uptime-loop"; +import { introCheck } from "../utils/intro-check"; @Discord() export class Ready { @@ -12,9 +12,6 @@ export class Ready { await client.initApplicationCommands(); await client.guilds.fetch(); const members = client.guilds.cache.get(Bun.env.GUILD!)?.members; - if(!((await stat("data")).isDirectory())) { - await mkdir("data") - } if (!(await Bun.file("bump.json").exists())) { await Bun.write("bump.json", "{}"); } @@ -23,5 +20,6 @@ export class Ready { } bumpRemind(client); uptimeLoop(client); + introCheck(client); } } diff --git a/src/index.ts b/src/index.ts index 80a3980..34cc307 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,7 +22,9 @@ const client = new Client({ client.on("error", console.error); const run = async () => { - await importx(`${dirname(import.meta.url)}/{events,commands,components}/**/*.ts`); + await importx( + `${dirname(import.meta.url)}/{events,commands,components}/**/*.ts`, + ); client.login(Bun.env.TOKEN!); }; diff --git a/src/utils/intro-check.ts b/src/utils/intro-check.ts new file mode 100644 index 0000000..6d8667e --- /dev/null +++ b/src/utils/intro-check.ts @@ -0,0 +1,22 @@ +import type { Client } from "discordx"; +import db from "../db"; +import { introTable } from "../db/schema"; +import type { TextChannel } from "discord.js"; +import { sleep } from "./underage"; + +export const introCheck = async (client: Client) => { + while (true) { + const channelRes = await db.select().from(introTable); + for (const c of channelRes) { + const channel = client.channels.cache.get(c.channel) as TextChannel; + const guild = client.guilds.cache.get(c.guild); + const msgs = await channel.messages.fetch({ limit: 10 }); + for (const m of msgs) { + if (!guild?.members.cache.has(m[1].author.id)) { + await m[1].delete(); + } + } + } + await sleep(1000 * 60 * 20); + } +}; diff --git a/src/utils/uptime-loop.ts b/src/utils/uptime-loop.ts index 1d601d1..afc9854 100644 --- a/src/utils/uptime-loop.ts +++ b/src/utils/uptime-loop.ts @@ -1,16 +1,19 @@ import type { Client } from "discordx"; import { sleep } from "./underage"; import type { TextChannel } from "discord.js"; +import db from "../db"; +import { uptimeTable } from "../db/schema"; export const uptimeLoop = async (client: Client) => { while (true) { await sleep(30 * 1000); - const channel = client.channels.cache.get( - Bun.env.SCYTHE_CHANNEL, - ) as TextChannel; - const msg = await channel.messages.fetch(Bun.env.UPTIME_MESSAGE); - await msg.edit( - `bot is up, last ping: | if the ping was more than 1 minute ago, cosmic needs to check the bot lol :3`, - ); + const uptimeRes = await db.select().from(uptimeTable); + for (const i of uptimeRes) { + const channel = client.channels.cache.get(i.channel) as TextChannel; + const msg = await channel.messages.fetch(i.message); + await msg.edit( + `bot is up, last ping: | if the ping was more than 1 minute ago, cosmic needs to check the bot lol :3`, + ); + } } };