From 5cf1d4f58dcf72c374cd64083264b4605d7a5caa Mon Sep 17 00:00:00 2001 From: rainy Date: Tue, 6 May 2025 14:57:39 -0700 Subject: [PATCH] starboard --- src/commands/starboard.ts | 71 +++++ src/components/ticket.ts | 10 +- .../migrations/0005_shallow_dragon_lord.sql | 10 + src/db/migrations/meta/0005_snapshot.json | 269 ++++++++++++++++++ src/db/migrations/meta/_journal.json | 7 + src/db/schema.ts | 11 + src/events/reactionAdd.ts | 38 +++ src/index.ts | 2 + 8 files changed, 413 insertions(+), 5 deletions(-) create mode 100644 src/commands/starboard.ts create mode 100644 src/db/migrations/0005_shallow_dragon_lord.sql create mode 100644 src/db/migrations/meta/0005_snapshot.json create mode 100644 src/events/reactionAdd.ts diff --git a/src/commands/starboard.ts b/src/commands/starboard.ts new file mode 100644 index 0000000..07a23b8 --- /dev/null +++ b/src/commands/starboard.ts @@ -0,0 +1,71 @@ +import { + ApplicationCommandOptionType, + CommandInteraction, + MessageFlags, + TextChannel, +} from "discord.js"; +import { Discord, Slash, SlashOption } from "discordx"; +import db from "../db"; +import { starboardSettingsTable } from "../db/schema"; +import { eq } from "drizzle-orm"; + +@Discord() +export class StarboardCmds { + @Slash({ name: "starboard-setup", description: "setup the starboard" }) + async starboardSetup( + @SlashOption({ + name: "channel", + description: "channel to post starboard messages to", + type: ApplicationCommandOptionType.Channel, + required: true, + }) + channel: TextChannel, + @SlashOption({ + name: "threshold", + description: "number of reacts needed to post to starboard", + type: ApplicationCommandOptionType.Integer, + required: true, + }) + threshold: number, + inter: CommandInteraction, + ) { + if (inter.user.id !== inter.guild?.ownerId) { + return await inter.reply("can't use this one silly!"); + } + await db.insert(starboardSettingsTable).values({ + guild: inter.guildId!, + channel: channel.id, + threshold, + enabled: 1, + }); + await inter.reply({ content: "Done", flags: MessageFlags.Ephemeral }); + } + @Slash({ + name: "starboard-enable", + description: "enable/disable the starboard", + }) + async starboardEnable( + @SlashOption({ + name: "setting", + description: "enable/disable", + type: ApplicationCommandOptionType.Boolean, + required: true, + }) + setting: boolean, + inter: CommandInteraction, + ) { + if (inter.user.id !== inter.guild?.ownerId) { + return await inter.reply("can't use this one silly!"); + } + await db + .update(starboardSettingsTable) + .set({ + enabled: setting ? 1 : 0, + }) + .where(eq(starboardSettingsTable.guild, inter.guildId!)); + await inter.reply({ + content: "Setting Changed", + flags: MessageFlags.Ephemeral, + }); + } +} diff --git a/src/components/ticket.ts b/src/components/ticket.ts index 97883d7..82a4175 100644 --- a/src/components/ticket.ts +++ b/src/components/ticket.ts @@ -55,13 +55,13 @@ export class TicketComponenets { PermissionsBitField.Flags.SendMessages, ], }, - { - id: inter.client.user.id, - allow: [ + { + id: inter.client.user.id, + allow: [ PermissionsBitField.Flags.ViewChannel, - PermissionsBitField.Flags.SendMessages + PermissionsBitField.Flags.SendMessages, ], - } + }, ], }); diff --git a/src/db/migrations/0005_shallow_dragon_lord.sql b/src/db/migrations/0005_shallow_dragon_lord.sql new file mode 100644 index 0000000..f4c7642 --- /dev/null +++ b/src/db/migrations/0005_shallow_dragon_lord.sql @@ -0,0 +1,10 @@ +CREATE TABLE `starboard_messages` ( + `message` text PRIMARY KEY NOT NULL +); +--> statement-breakpoint +CREATE TABLE `starboard_settings` ( + `guild` text PRIMARY KEY NOT NULL, + `threshold` integer NOT NULL, + `channel` text NOT NULL, + `enabled` integer NOT NULL +); diff --git a/src/db/migrations/meta/0005_snapshot.json b/src/db/migrations/meta/0005_snapshot.json new file mode 100644 index 0000000..480382e --- /dev/null +++ b/src/db/migrations/meta/0005_snapshot.json @@ -0,0 +1,269 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "f14a1768-d64d-47dc-a9bd-ad3646ab3c6e", + "prevId": "dea3a962-3fb8-4c45-90fa-baff2f53bfb2", + "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": {} + }, + "confess": { + "name": "confess", + "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": {} + }, + "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": {} + }, + "starboard_messages": { + "name": "starboard_messages", + "columns": { + "message": { + "name": "message", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "starboard_settings": { + "name": "starboard_settings", + "columns": { + "guild": { + "name": "guild", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "threshold": { + "name": "threshold", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "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": {} + }, + "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 867b728..ccf138e 100644 --- a/src/db/migrations/meta/_journal.json +++ b/src/db/migrations/meta/_journal.json @@ -36,6 +36,13 @@ "when": 1744606507294, "tag": "0004_keen_bedlam", "breakpoints": true + }, + { + "idx": 5, + "version": "6", + "when": 1746568313383, + "tag": "0005_shallow_dragon_lord", + "breakpoints": true } ] } diff --git a/src/db/schema.ts b/src/db/schema.ts index f318505..e3d85f0 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -41,4 +41,15 @@ export const confessTable = sqliteTable("confess", { channel: text().notNull(), }); +export const starboardMessagesTable = sqliteTable("starboard_messages", { + message: text().primaryKey(), +}); + +export const starboardSettingsTable = sqliteTable("starboard_settings", { + guild: text().primaryKey(), + threshold: int().notNull(), + channel: text().notNull(), + enabled: int().notNull(), +}); + export type ColonThreeType = InferSelectModel; diff --git a/src/events/reactionAdd.ts b/src/events/reactionAdd.ts new file mode 100644 index 0000000..953da7b --- /dev/null +++ b/src/events/reactionAdd.ts @@ -0,0 +1,38 @@ +import { Client, Discord, On, type ArgsOf } from "discordx"; +import db from "../db"; +import { starboardMessagesTable, starboardSettingsTable } from "../db/schema"; +import { eq } from "drizzle-orm"; +import { Colors, EmbedBuilder, TextChannel } from "discord.js"; + +@Discord() +export class ReactionAdd { + @On({ event: "messageReactionAdd" }) + async reactionAdd([re]: ArgsOf<"messageReactionAdd">, client: Client) { + const settings = await db + .select() + .from(starboardSettingsTable) + .where(eq(starboardSettingsTable.guild, re.message.guildId!)); + if ( + re.count == settings[0].threshold && + re.emoji.name == "⭐" && + re.message.channelId !== settings[0].channel && + settings[0].enabled == 1 + ) { + await db + .insert(starboardMessagesTable) + .values({ message: re.message.id }); + const author = client.guilds.cache + .get(re.message.guildId!)! + .members.cache.get(re.message.author!.id); + const embed = new EmbedBuilder() + .setTitle(`New message from ${author?.displayName}`) + .setDescription(re.message.content) + .setColor(Colors.Yellow); + + const channel = client.channels.cache.get( + settings[0].channel, + ) as TextChannel; + await channel.send({ embeds: [embed] }); + } + } +} diff --git a/src/index.ts b/src/index.ts index 34cc307..43e658e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,8 @@ const client = new Client({ IntentsBitField.Flags.GuildMessages, IntentsBitField.Flags.GuildMembers, IntentsBitField.Flags.MessageContent, + IntentsBitField.Flags.GuildMessageReactions, + IntentsBitField.Flags.DirectMessageReactions, ], silent: false, });