From e8f797d1e0b5cf181622ee9d63858c93d3c9685c Mon Sep 17 00:00:00 2001 From: Louis Hollingworth Date: Sun, 18 Jun 2023 12:34:31 +0100 Subject: [PATCH] (#2) Booster roles can now be linked to members. Next steps: * Remove booster roles from the DB and Guild when someone stops boosting * Add booster roles to the DB and Guild when someone starts boosting Signed-off-by: Louis Hollingworth --- .../migration.sql | 26 +++++++ prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 6 ++ src/commands/admin.ts | 74 +++++++++++++++---- src/events/common.ts | 10 --- src/events/guild_join.ts | 15 ++++ src/main.ts | 22 +----- 7 files changed, 111 insertions(+), 45 deletions(-) create mode 100644 prisma/migrations/20230618111706_add_member_model/migration.sql create mode 100644 prisma/migrations/migration_lock.toml delete mode 100644 src/events/common.ts create mode 100644 src/events/guild_join.ts diff --git a/prisma/migrations/20230618111706_add_member_model/migration.sql b/prisma/migrations/20230618111706_add_member_model/migration.sql new file mode 100644 index 0000000..e22ec0e --- /dev/null +++ b/prisma/migrations/20230618111706_add_member_model/migration.sql @@ -0,0 +1,26 @@ +-- CreateTable +CREATE TABLE "guild" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "reports_channel_id" TEXT, + + CONSTRAINT "guild_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "member" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "booster_role_id" TEXT NOT NULL, + + CONSTRAINT "member_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "guild_id_key" ON "guild"("id"); + +-- CreateIndex +CREATE UNIQUE INDEX "member_id_key" ON "member"("id"); + +-- CreateIndex +CREATE UNIQUE INDEX "member_booster_role_id_key" ON "member"("booster_role_id"); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index fc1e6d5..5e425e7 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -12,3 +12,9 @@ model guild { name String reports_channel_id String? } + +model member { + id String @id @unique + name String + booster_role_id String @unique +} diff --git a/src/commands/admin.ts b/src/commands/admin.ts index 405a3eb..8e54a18 100644 --- a/src/commands/admin.ts +++ b/src/commands/admin.ts @@ -4,6 +4,7 @@ import { CommandInteraction, GuildMember, PermissionsBitField, + Role, } from "discord.js"; import { Discord, @@ -15,24 +16,14 @@ import { } from "discordx"; import { prisma } from "../main.js"; -const AdminOnly: GuardFunction = async ( - arg, - client, - next -) => { - const argObj = arg instanceof Array ? arg[0] : arg; - const user = argObj.user as GuildMember; - - if (user.permissions.has(PermissionsBitField.Flags.Administrator)) - await next(); -}; - @Discord() @SlashGroup({ name: "admin", description: "Admin commands" }) @SlashGroup("admin") -@Guard(AdminOnly) -class AdminCmds { - @Slash({ description: "Set or get the configured channel for reports" }) +export class AdminCmds { + @Slash({ + description: "Set or get the configured channel for reports", + defaultMemberPermissions: PermissionsBitField.Flags.Administrator, + }) async reports( @SlashOption({ description: "Set where the reports should be sent", @@ -92,4 +83,57 @@ class AdminCmds { }); } } + + @Slash({ + description: "Link a user to their booster role", + name: "link_role", + defaultMemberPermissions: PermissionsBitField.Flags.ManageRoles, + }) + async link_role( + @SlashOption({ + description: "The user account to link", + name: "member", + required: true, + type: ApplicationCommandOptionType.User, + }) + member: GuildMember, + @SlashOption({ + description: "The role to link", + name: "role", + required: true, + type: ApplicationCommandOptionType.Role, + }) + role: Role, + interaction: CommandInteraction + ) { + let mem = await prisma.member.findUnique({ + where: { + id: member.id, + }, + }); + + if (mem) { + await prisma.member.update({ + where: { + id: member.id, + }, + data: { + name: mem.name != member.displayName ? member.displayName : undefined, + booster_role_id: role.id, + }, + }); + } else { + await prisma.member.create({ + data: { + id: member.id, + name: member.displayName, + booster_role_id: role.id, + }, + }); + } + interaction.reply({ + content: "Member booster role updated!", + ephemeral: true, + }); + } } diff --git a/src/events/common.ts b/src/events/common.ts deleted file mode 100644 index 3a4e946..0000000 --- a/src/events/common.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { ArgsOf, Client } from "discordx"; -import { Discord, On } from "discordx"; - -@Discord() -export class Example { - @On() - messageDelete([message]: ArgsOf<"messageDelete">, client: Client): void { - console.log("Message Deleted", client.user?.username, message.content); - } -} diff --git a/src/events/guild_join.ts b/src/events/guild_join.ts new file mode 100644 index 0000000..f6ac659 --- /dev/null +++ b/src/events/guild_join.ts @@ -0,0 +1,15 @@ +import { ArgsOf, Discord, On } from "discordx"; +import { prisma } from "../main.js"; + +@Discord() +export class GuildJoin { + @On({ event: "guildCreate" }) + fn([guild]: ArgsOf<"guildCreate">) { + prisma.guild.create({ + data: { + id: guild.id, + name: guild.name, + }, + }); + } +} diff --git a/src/main.ts b/src/main.ts index 9e8fa97..a4b9038 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,5 @@ import { dirname, importx } from "@discordx/importer"; -import type { Guild, Interaction, Message } from "discord.js"; +import type { Interaction } from "discord.js"; import { IntentsBitField } from "discord.js"; import * as dotenv from "dotenv"; import { Client } from "discordx"; @@ -23,16 +23,11 @@ export const bot = new Client({ // Debug logs are disabled in silent mode silent: false, - - // Configuration for @SimpleCommand - simpleCommand: { - prefix: "!", - }, }); bot.once("ready", async () => { // Make sure all guilds are cached - // await bot.guilds.fetch(); + await bot.guilds.fetch(); // Synchronize applications commands with Discord await bot.initApplicationCommands(); @@ -52,19 +47,6 @@ bot.on("interactionCreate", (interaction: Interaction) => { bot.executeInteraction(interaction); }); -bot.on("messageCreate", (message: Message) => { - bot.executeCommand(message); -}); - -bot.on("guildCreate", (guild: Guild) => { - prisma.guild.create({ - data: { - id: guild.id, - name: guild.name, - }, - }); -}); - async function run() { // The following syntax should be used in the commonjs environment //