diff --git a/src/classes/primary.ts b/src/classes/primary.ts index 495d8d0..5e7d324 100644 --- a/src/classes/primary.ts +++ b/src/classes/primary.ts @@ -20,8 +20,11 @@ export default class DynamicaPrimary { /** The prisma guild */ prismaGuild: Prisma.Guild; - constructor(client: Client) { + constructor(client: Client, channelId?: string) { this.client = client; + if (channelId) { + this.id = channelId; + } } /** @@ -52,38 +55,23 @@ export default class DynamicaPrimary { logger.debug( `New primary channel ${channel.name} created by ${primary.creator}.` ); - await this.fetch(channel.id); + await this.fetch(); } catch (error) { logger.error("Error creating new primary channel:", error); } return this; } - /** - * Checks the database to see if the channel exists - * @param id The channel Id - * @returns boolean based on if a primary channel exists within the database - */ - async exists(id: string): Promise { - let primary = await db.primary.findUnique({ - where: { id }, - }); - if (!!primary) { - this.id = id; - } - return !!primary; - } - /** * Fetch the database entry and discord channels (voice and text). * @param channelId The discord channel Id. */ - async fetch(channelId?: string): Promise { + async fetch(): Promise { if (!this.client) { throw new Error("No client defined"); } - if (channelId) { - this.id = channelId; + if (!this.id) { + throw new Error("No id defined"); } let primary = await db.primary.findUnique({ where: { id: this.id }, @@ -174,7 +162,7 @@ export default class DynamicaPrimary { await this.discord.delete(); - logger.debug(`Secondary channel deleted ${this.id}.`); + logger.debug(`Primary channel deleted ${this.id}.`); } catch (error) { logger.error("Failed to delete primary:", error); } diff --git a/src/classes/secondary.ts b/src/classes/secondary.ts index 5742bd0..87d3149 100644 --- a/src/classes/secondary.ts +++ b/src/classes/secondary.ts @@ -25,15 +25,21 @@ export default class DynamicaSecondary { id: string; /** The discord text channel */ textChannel?: TextChannel; - /** The discord guild */ - discordGuild: Guild; /** The prisma guild */ prismaGuild: Prisma.Guild; /** The prisma primary */ prismaPrimary: Prisma.Primary; - constructor(client: Client) { + /** + * The secondary constructor + * @param client DiscordJS client instance + * @param id The channel Id + */ + constructor(client: Client, id?: string) { this.client = client; + if (id) { + this.id = id; + } } /** @@ -96,51 +102,32 @@ export default class DynamicaSecondary { await member.voice.setChannel(secondary); - const textChannelId = async () => { - if (primaryConfig.guild?.textChannelsEnabled && member) { - const textChannel = await guild.channels.create("Text Channel", { - type: "GUILD_TEXT", - topic: `Private text channel for members of <#${secondary.id}>.`, - permissionOverwrites: [ - { id: guild.channels.guild.roles.everyone, deny: "VIEW_CHANNEL" }, - { id: member?.id, allow: "VIEW_CHANNEL" }, - ], - parent: secondary.parent ?? undefined, - }); - await textChannel.send({ - embeds: [ - new Embed() - .setTitle("Welcome!") - .setColor(3447003) - .setDescription( - `Welcome to your very own private text chat. This channel is only to people in <#${secondary.id}>.` - ) - .setAuthor({ - name: "Dynamica", - url: "https://dynamica.dev", - iconURL: "https://dynamica.dev/img/dynamica.png", - }), - ], - }); - return textChannel.id; - } - }; - - await db.secondary.create({ - data: { - id: secondary.id, - creator: member?.id, - primaryId: primary.id, - guildId: guild.id, - textChannelId: await textChannelId(), - }, - }); + db.secondary + .create({ + data: { + id: secondary.id, + creator: member.id, + primaryId: primary.id, + guildId: guild.id, + }, + include: { guild: true, primary: true }, + }) + .then(async (channel) => { + this.id = secondary.id; + this.prisma = channel; + this.prismaGuild = channel.guild; + this.prismaPrimary = channel.primary; + const guild = await db.guild.findUnique({ where: { id: this.id } }); + if (guild?.textChannelsEnabled) { + this.createTextChannel(member); + } + updateActivityCount(this.client); + }); - await updateActivityCount(this.client); - await this.fetch(secondary.id); logger.debug( `Secondary channel ${secondary.name} created by ${member?.user.tag} in ${guild.name}.` ); + this.discord = secondary; } catch (error) { logger.error(error); } @@ -148,85 +135,105 @@ export default class DynamicaSecondary { } /** - * Checks the database to see if the channel exists - * @param id The channel Id - * @returns boolean based on if a secondary channel exists within the database + * Create a text channel. + * @param member The person who created the channel */ - async exists(id: string): Promise { - let secondary = await db.secondary.findUnique({ - where: { id }, - }); - return !!secondary; + async createTextChannel(member: GuildMember) { + if (!this.id) { + throw new Error("No Id defined"); + } + try { + const textChannel = await this.discord.guild.channels.create( + "Text Channel", + { + type: "GUILD_TEXT", + topic: `Private text channel for members of <#${this.id}>.`, + permissionOverwrites: [ + { + id: this.discord.guild.channels.guild.roles.everyone, + deny: "VIEW_CHANNEL", + }, + { id: member.id, allow: "VIEW_CHANNEL" }, + ], + parent: this.discord.parent ?? undefined, + } + ); + await textChannel.send({ + embeds: [ + new Embed() + .setTitle("Welcome!") + .setColor(3447003) + .setDescription( + `Welcome to your very own private text chat. This channel is only to people in <#${this.id}>.` + ) + .setAuthor({ + name: "Dynamica", + url: "https://dynamica.dev", + iconURL: "https://dynamica.dev/img/dynamica.png", + }), + ], + }); + this.textChannel = textChannel; + await db.secondary.update({ + where: { id: this.id }, + data: { + textChannelId: textChannel.id, + }, + }); + } catch (error) { + logger.error("Failed to create text channel:", error); + } } /** * Fetch the database entry and discord channels (voice and text). * @param channelId The discord channel Id. */ - async fetch(channelId?: string): Promise { + async fetch(): Promise { + // Variables if (!this.client) { throw new Error("No client defined"); } - if (channelId) { - this.id = channelId; + if (!this.id) { + throw new Error("No Id defined"); } - const id = this.id ?? channelId; - try { - let secondary = await db.secondary.findUnique({ - where: { id }, - include: { guild: true, primary: true }, - }); + const { id } = this; - if (!secondary) return undefined; - - this.prisma = secondary; - this.prismaGuild = secondary.guild; - - this.prismaPrimary = secondary.primary; - if (secondary.textChannelId) { - try { - let textChannel = await this.client.channels.cache.get( - this.prisma.textChannelId - ); - if (!textChannel) { - this.textChannel = undefined; - } else { - if ( - textChannel.isText() && - textChannel.type !== "DM" && - textChannel.type !== "GUILD_NEWS" && - !textChannel.isThread() - ) { - this.textChannel = textChannel; - } else { - throw new Error("Not a valid text channel."); - } - } - } catch (error) { - logger.error("Failed to save text channel:", error); - } - } - } catch (error) { - logger.error("Error fetching secondary channel from database:", error); - } - try { - let channel = await this.client.channels.cache.get(id); - if (!channel) { - await db.secondary.delete({ where: { id } }); + const prisma = await db.secondary.findUnique({ + where: { id }, + include: { guild: true, primary: true }, + }); + + if (prisma) { + const discord = await this.client.channels.cache.get(id); + if (discord?.type === "GUILD_VOICE") { + this.discord = discord; + } else { + await db.secondary.delete({ where: { id: prisma.id } }); return undefined; } - if (!channel.isVoice()) { - throw new Error("Not a valid voice channel."); - } else if (channel.type === "GUILD_STAGE_VOICE") { - throw new Error("Not a valid voice channel (Stage)"); + const textChannel = await this.client.channels.cache.get( + prisma.textChannelId + ); + this.prisma = prisma; + this.prismaGuild = prisma.guild; + this.prismaPrimary = prisma.primary; + if (textChannel?.type === "GUILD_TEXT") { + this.textChannel = textChannel; } else { - this.discord = channel; - this.discordGuild = channel.guild; + this.textChannel = undefined; + await db.secondary.update({ + where: { id }, + data: { + textChannelId: undefined, + }, + }); } - } catch (error) { - logger.error("Error fetching secondary channel from discord:", error); + } else { + return undefined; } + return this; } @@ -343,26 +350,25 @@ export default class DynamicaSecondary { if (!this.client) { throw new Error("No client defined"); } - if (!this.discord) { - try { + if (!this.id) { + logger.debug("No id"); + } + try { + if (!this.discord && !this.prisma) { + return; + } else if (!this.discord && !!this.prisma) { await this.deletePrisma(); - } catch (error) { - logger.error("Failed to delete prisma secondary entry:", error); - } - } else if (!this.prisma) { - try { + } else if (!this.prisma && !!this.discord) { await this.deleteDiscord(); - } catch (error) { - logger.error("Failed to delete discord secondary:", error); - } - } else if (this.discord && this.prisma) { - try { + } else if (this.discord && this.prisma) { await this.deletePrisma(); await this.deleteDiscord(); - } catch (error) { - logger.error("Failed to delete secondary:", error); } + logger.debug(`Secondary channel deleted ${this.id}.`); + } catch (error) { + logger.error(error); } + await updateActivityCount(this.client); } @@ -395,8 +401,6 @@ export default class DynamicaSecondary { ); await textChannel.delete(); } - - logger.debug(`Secondary channel deleted ${this.id}.`); } catch (error) { logger.error("Failed to delete secondary:", error); } diff --git a/src/commands/allyourbase.ts b/src/commands/allyourbase.ts index 654031a..977ac80 100644 --- a/src/commands/allyourbase.ts +++ b/src/commands/allyourbase.ts @@ -24,8 +24,9 @@ export const allyourbase = new Command() const { channelId } = guildMember.voice; const secondaryChannel = await new DynamicaSecondary( - interaction.client - ).fetch(channelId); + interaction.client, + channelId + ).fetch(); if (secondaryChannel) { await secondaryChannel.changeOwner(interaction.user); diff --git a/src/commands/general.ts b/src/commands/general.ts index 3ccc4bc..31ffb1f 100644 --- a/src/commands/general.ts +++ b/src/commands/general.ts @@ -39,8 +39,9 @@ export const general = new Command() updatedPrimary.secondaries.forEach(async (secondary) => { const dynamicaSecondary = await new DynamicaSecondary( - interaction.client - ).fetch(secondary.id); + interaction.client, + secondary.id + ).fetch(); dynamicaSecondary?.update(); }); diff --git a/src/commands/info.ts b/src/commands/info.ts index 00bb4db..c8bc9d9 100644 --- a/src/commands/info.ts +++ b/src/commands/info.ts @@ -2,6 +2,7 @@ import { Embed, SlashCommandBuilder } from "@discordjs/builders"; import Command from "../classes/command.js"; import DynamicaPrimary from "../classes/primary.js"; import DynamicaSecondary from "../classes/secondary.js"; +import { db } from "../utils/db.js"; export const info = new Command() .setCommandData( @@ -30,6 +31,11 @@ export const info = new Command() ) .setDescription("Get info about a secondary channel.") ) + .addSubcommand((subcommand) => + subcommand + .setName("guild") + .setDescription("Get info about the guil's settings.") + ) ) .setHelpText("Shows the info of either a user or the current server.") .setResponse(async (interaction) => { @@ -37,9 +43,10 @@ export const info = new Command() switch (subcommand) { case "primary": const chosenPrimary = interaction.options.getString("primarychannel"); - const primary = await new DynamicaPrimary(interaction.client).fetch( + const primary = await new DynamicaPrimary( + interaction.client, chosenPrimary - ); + ).fetch(); interaction.reply({ ephemeral: true, content: `Here's the current info for <#${primary.id}>`, @@ -65,9 +72,10 @@ export const info = new Command() case "secondary": const chosenSecondary = interaction.options.getString("secondarychannel"); - const secondary = await new DynamicaSecondary(interaction.client).fetch( + const secondary = await new DynamicaSecondary( + interaction.client, chosenSecondary - ); + ).fetch(); interaction.reply({ ephemeral: true, content: `Here's the current info for <#${secondary.id}>`, @@ -95,7 +103,27 @@ export const info = new Command() ], }); break; - + case "guild": + const prismaGuild = await db.guild.findUnique({ + where: { id: interaction.guildId }, + }); + interaction.reply({ + ephemeral: true, + content: `Here's the current info for the guild`, + embeds: [ + new Embed().addFields( + { + name: "Text Channels", + value: prismaGuild.textChannelsEnabled ? "Enabled" : "Disabled", + }, + { + name: "Join Requests", + value: prismaGuild.allowJoinRequests ? "Enabled" : "Disabled", + } + ), + ], + }); + break; default: break; } diff --git a/src/commands/lock.ts b/src/commands/lock.ts index e4a1376..c012165 100644 --- a/src/commands/lock.ts +++ b/src/commands/lock.ts @@ -27,8 +27,9 @@ export const lock = new Command() const channelId = guildMember?.voice.channelId; const dynamicaSecondary = await new DynamicaSecondary( - interaction.client - ).fetch(channelId); + interaction.client, + channelId + ).fetch(); if (dynamicaSecondary) { await dynamicaSecondary.lock(); diff --git a/src/commands/name.ts b/src/commands/name.ts index bad5eb5..644bedf 100644 --- a/src/commands/name.ts +++ b/src/commands/name.ts @@ -33,9 +33,10 @@ export const name = new Command() await db.secondary.update({ where: { id: channel.id }, data: { name } }); logger.info(`${channel.id} name changed.`); - const secondary = await new DynamicaSecondary(interaction.client).fetch( + const secondary = await new DynamicaSecondary( + interaction.client, channel.id - ); + ).fetch(); secondary.update(); return interaction.reply(`Channel name changed to \`${name}\`.`); }); diff --git a/src/commands/template.ts b/src/commands/template.ts index 44baadc..2ddbd16 100644 --- a/src/commands/template.ts +++ b/src/commands/template.ts @@ -40,8 +40,9 @@ export const template = new Command() primary.secondaries.forEach(async (secondary) => { const dynamicaSecondary = await new DynamicaSecondary( - interaction.client - ).fetch(secondary.id); + interaction.client, + secondary.id + ).fetch(); dynamicaSecondary.update(); }); diff --git a/src/commands/text.ts b/src/commands/text.ts index 1c07a57..e75d47b 100644 --- a/src/commands/text.ts +++ b/src/commands/text.ts @@ -24,15 +24,14 @@ export const text = new Command() ) .setResponse(async (interaction) => { const state = interaction.options.getBoolean("state", true); - - db.guild.update({ + const guild = await db.guild.update({ where: { id: interaction.guildId }, data: { textChannelsEnabled: state }, }); - return interaction.reply( + await interaction.reply( `Temporary text channels ${ - !state ? "disabled" : "enabled" + guild.textChannelsEnabled ? "enabled" : "disabled" } for all future created channels.` ); }); diff --git a/src/commands/transfer.ts b/src/commands/transfer.ts index bb4654f..2e16125 100644 --- a/src/commands/transfer.ts +++ b/src/commands/transfer.ts @@ -31,8 +31,9 @@ export const transfer = new Command() const { channelId } = guildMember.voice; const secondaryChannel = await new DynamicaSecondary( - interaction.client - ).fetch(channelId); + interaction.client, + channelId + ).fetch(); if (secondaryChannel) { await secondaryChannel.changeOwner(user); interaction.reply( diff --git a/src/commands/unlock.ts b/src/commands/unlock.ts index af54019..49343de 100644 --- a/src/commands/unlock.ts +++ b/src/commands/unlock.ts @@ -62,8 +62,9 @@ export const unlock = new Command() const { channelId } = guildMember.voice; const dynamicaSecondary = await new DynamicaSecondary( - interaction.client - ).fetch(channelId); + interaction.client, + channelId + ).fetch(); if (dynamicaSecondary) { await dynamicaSecondary.unlock(); diff --git a/src/events/channelDelete.ts b/src/events/channelDelete.ts index b29f0e0..68e5960 100644 --- a/src/events/channelDelete.ts +++ b/src/events/channelDelete.ts @@ -8,10 +8,14 @@ export const channelDelete = new Event() .setEvent("channelDelete") .setResponse(async (channel: Channel | DMChannel) => { // logger.debug(channel); - const primary = await new DynamicaPrimary(channel.client).fetch(channel.id); - const secondary = await new DynamicaSecondary(channel.client).fetch( + const primary = await new DynamicaPrimary( + channel.client, channel.id - ); + ).fetch(); + const secondary = await new DynamicaSecondary( + channel.client, + channel.id + ).fetch(); if (primary) { primary.delete(); diff --git a/src/events/presenceUpdate.ts b/src/events/presenceUpdate.ts index 4155011..653bc02 100644 --- a/src/events/presenceUpdate.ts +++ b/src/events/presenceUpdate.ts @@ -13,8 +13,9 @@ export const presenceUpdate = new Event() return; const { channelId } = newPresence.member.voice; const dynamicaSecondary = await new DynamicaSecondary( - newPresence.client - ).fetch(channelId); + newPresence.client, + channelId + ).fetch(); if (dynamicaSecondary) { dynamicaSecondary.update(); diff --git a/src/events/ready.ts b/src/events/ready.ts index b941dd9..86e0cb3 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -15,9 +15,10 @@ export const ready = new Event() const primaries = await db.primary.findMany(); primaries.forEach(async (element) => { - const existingPrimary = await new DynamicaPrimary(client).fetch( + const existingPrimary = await new DynamicaPrimary( + client, element.id - ); + ).fetch(); if (!existingPrimary) { return; @@ -40,9 +41,10 @@ export const ready = new Event() }); secondaries.forEach(async (element) => { - const secondaryChannel = await new DynamicaSecondary(client).fetch( + const secondaryChannel = await new DynamicaSecondary( + client, element.id - ); + ).fetch(); await secondaryChannel?.update(); }); diff --git a/src/events/voiceStateUpdate.ts b/src/events/voiceStateUpdate.ts index e3a13e4..2150178 100644 --- a/src/events/voiceStateUpdate.ts +++ b/src/events/voiceStateUpdate.ts @@ -2,6 +2,7 @@ import { VoiceState } from "discord.js"; import Event from "../classes/event.js"; import DynamicaPrimary from "../classes/primary.js"; import DynamicaSecondary from "../classes/secondary.js"; +import { logger } from "../utils/logger.js"; export const voiceStateUpdate = new Event() .setOnce(false) @@ -14,13 +15,15 @@ export const voiceStateUpdate = new Event() if (newVoiceState.channel && newVoiceState.member) { /** Look for an existing secondary channel */ const existingSecondary = await new DynamicaSecondary( - newVoiceState.client - ).fetch(newVoiceState.channelId); + newVoiceState.client, + newVoiceState.channelId + ).fetch(); /** Look for an existing primary channel */ - const primary = await new DynamicaPrimary(newVoiceState.client).fetch( + const primary = await new DynamicaPrimary( + newVoiceState.client, newVoiceState.channelId - ); + ).fetch(); // Create a new secondary if one doesn't already exist and the user has joined a primary channel if (!!primary) { @@ -49,9 +52,10 @@ export const voiceStateUpdate = new Event() // User leaves channel if (oldVoiceState.channel && oldVoiceState.member) { - const secondary = await new DynamicaSecondary(oldVoiceState.client).fetch( + const secondary = await new DynamicaSecondary( + oldVoiceState.client, oldVoiceState.channelId - ); + ).fetch(); if (!!secondary) { if (oldVoiceState.channel.members.size !== 0) { @@ -64,6 +68,7 @@ export const voiceStateUpdate = new Event() } else { // const debouncedDelete = pDebounce(secondary.delete, 1000); // await debouncedDelete(); + logger.log("Called delete"); secondary.delete(); } }