From 8c146f639e2deed879cc034316f4709d9c942b26 Mon Sep 17 00:00:00 2001 From: Kevin Siniecki Date: Tue, 28 Nov 2023 15:15:02 +0100 Subject: [PATCH] added queue activity channel (#14) --- src/commands/queue/join.ts | 41 +++---------- src/commands/setqueueactivity.ts | 94 +++++++++++++++++++++++++++++ src/events/VoiceStateUpdateEvent.ts | 12 ++-- src/models/text_channels.ts | 10 ++- src/utils/general.ts | 35 +++++++++-- 5 files changed, 146 insertions(+), 46 deletions(-) create mode 100644 src/commands/setqueueactivity.ts diff --git a/src/commands/queue/join.ts b/src/commands/queue/join.ts index 75cfedb..0b427df 100644 --- a/src/commands/queue/join.ts +++ b/src/commands/queue/join.ts @@ -1,11 +1,9 @@ -import { ApplicationCommandOptionType, Message } from "discord.js"; +import {ApplicationCommandOptionType, Message} from "discord.js"; import { Command } from "../../../typings"; import {GuildModel} from "../../models/guilds"; import {UserModel} from "../../models/users"; -import { SessionModel } from "../../models/sessions"; -import { Queue } from "../../models/queues"; -import { ArraySubDocumentType } from "@typegoose/typegoose"; -import { Bot } from "../../bot"; +import {manageJoinQueue} from "../../utils/general"; + const command: Command = { name: "join", @@ -77,44 +75,19 @@ const command: Command = { intent: interaction.options.getString("intent") ?? undefined, }); - try { - const roles = await g.roles.fetch(); - const waiting_role = roles.find(x => x.name.toLowerCase() === queueData.name.toLowerCase() + "-waiting"); - - const member = g.members.resolve(user); - if (waiting_role && member && !member.roles.cache.has(waiting_role.id)) { - member.roles.add(waiting_role); - } - // await member?.voice.disconnect(); + await manageJoinQueue(g, guildData, user, queueData); } catch (error) { - console.log(error); + console.log(error) } + await client.utils.embeds.SimpleEmbed(interaction, { title: "Coaching System", text: queueData.getJoinMessage(user.id), empheral: true }); // await client.utils.embeds.SimpleEmbed(interaction, "TODO", `Command \`${path.relative(process.cwd(), __filename)}\` is not Implemented Yet.`); - - await informCoaches(client, queueData); + }, }; -/** - * sends a private message to all coaches having an active session on the given queue - * @param queueData queue the user joined in - */ -async function informCoaches(client: Bot, queueData: ArraySubDocumentType) { - const activeSessions = await SessionModel.find({ queue: queueData.id, active: true }).exec(); - try { - for(const session of activeSessions) { - const user = await client.users.fetch(session.user); - const dmChannel = await user.createDM(); - await client.utils.embeds.SimpleEmbed(dmChannel, { title: "Coaching System", text: `${user.displayName} has joined the queue: ${queueData.name}`, empheral: true }); - } - } catch (error) { - console.log(error) - } -} - /** * Exporting the Command using CommonJS diff --git a/src/commands/setqueueactivity.ts b/src/commands/setqueueactivity.ts new file mode 100644 index 0000000..4cbc64e --- /dev/null +++ b/src/commands/setqueueactivity.ts @@ -0,0 +1,94 @@ +import { + ApplicationCommandOptionType, + ChannelType, + GuildChannel, + Message, + TextChannel as DiscordTextChannel, +} from "discord.js"; +import { Command } from "../../typings"; +import { GuildModel } from "../models/guilds"; +import { FilterOutFunctionKeys } from "@typegoose/typegoose/lib/types"; +import {TextChannel} from "../models/text_channels"; + +const command: Command = { + name: "setqueueinfo", + description: "the given text chnnel will inform tutors with active sessions about queue activities", + aliases: ["sqi"], + usage: "[channel resolvable]", + cooldown: 5, + category: "Coaching", + guildOnly: true, + defaultPermission: false, + options: [{ + name: "queueinfochannel", + description: "the text channels name", + type: ApplicationCommandOptionType.Channel, + required: true, + }, + { + name: "queue", + description: "name of the queue", + type: ApplicationCommandOptionType.String, + required: true, + } + ], + execute: async (client, interaction, args) => { + if (!interaction) { + return; + } + if (interaction instanceof Message) { + await client.utils.embeds.SimpleEmbed(interaction, { title: "Slash Only Command", text: "This Command is Slash only but you Called it with The Prefix. use the slash Command instead.", deleteinterval: 3000 }); + if (interaction.deletable) await interaction.delete(); + return; + } + const member = client.utils.general.getMember(interaction); + if (!member || member.id !== client.config.get("ownerID") as string) { + await interaction?.reply("You do not have permission to execute this command."); + return; + } + + + // Find channel + const channel = interaction.options.getChannel("queueinfochannel", true); + if (!channel || !(channel instanceof GuildChannel)) { + return await interaction?.reply("Channel could not be found."); + } + if (!(channel instanceof DiscordTextChannel)) { + return await interaction?.reply("QueueInfoChannel channel must be a text Channel."); + } + + const g = interaction!.guild!; + const guildData = (await GuildModel.findById(g.id)); + + if (!guildData) { + return await client.utils.embeds.SimpleEmbed(interaction, { title: "Coaching System", text: "Guild Data Could not be found.", empheral: true }); + } + + const queue = interaction.options.getString("queue", true); + const queueData = guildData.queues.find(x => x.name === queue); + + const updated = await GuildModel.updateOne( + { _id: g.id }, + { + $push: { + "text_channels": { + _id: channel.id, + managed: true, + channel_type : ChannelType.GroupDM, + queue: queueData, + listen_for_commands: true, + category: channel.parent?.name + } as FilterOutFunctionKeys, + }, + }, + { upsert: true, setDefaultsOnInsert: true }, + ); + console.log(updated); + interaction!.reply({ content: `Success. ${channel.name} set to queue info channel for queue: ${queue}` }); + }, +}; + +/** + * Exporting the Command using CommonJS + */ +module.exports = command; \ No newline at end of file diff --git a/src/events/VoiceStateUpdateEvent.ts b/src/events/VoiceStateUpdateEvent.ts index 8621e9b..17bf2b7 100644 --- a/src/events/VoiceStateUpdateEvent.ts +++ b/src/events/VoiceStateUpdateEvent.ts @@ -1,10 +1,11 @@ import { ExecuteEvent } from "../../typings"; -import { Collection, ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js"; +import {Collection, ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder} from "discord.js"; import { GuildModel } from "../models/guilds"; import { QueueEntry } from "../models/queue_entry"; export const name = "voiceStateUpdate"; import { RoomModel } from "../models/rooms"; import { Event as EVT, eventType } from "../models/events"; +import {manageJoinQueue} from "../utils/general"; export const execute: ExecuteEvent<"voiceStateUpdate"> = async (client, oldState, newState) => { const oldUserChannel = oldState.channel; @@ -77,13 +78,10 @@ export const execute: ExecuteEvent<"voiceStateUpdate"> = async (client, oldState importance: 1, }); - const roles = await guild.roles.fetch(); - const waiting_role = roles.find(x => x.name.toLowerCase() === queue.name.toLowerCase() + "-waiting"); - const member = newState.member!; - if (waiting_role && member && !member.roles.cache.has(waiting_role.id)) { - member.roles.add(waiting_role); - } + if (guildData != null && newState.member!.user) + await manageJoinQueue(guild, guildData, newState.member!.user, queue) + } catch (error) { try { await client.utils.embeds.SimpleEmbed(await newState.member!.createDM(), { title: "Queue System", text: `An error occurred: ${error}` }); diff --git a/src/models/text_channels.ts b/src/models/text_channels.ts index dc4220a..4ee6adf 100644 --- a/src/models/text_channels.ts +++ b/src/models/text_channels.ts @@ -1,5 +1,6 @@ import { ChannelType, TextChannelType } from "discord.js"; -import { getModelForClass, prop } from "@typegoose/typegoose"; +import {getModelForClass, prop, Ref} from "@typegoose/typegoose"; +import {Queue} from "./queues"; /** * Database Representation of a Discord Channel @@ -25,6 +26,7 @@ export interface Channel { * The Channel owner */ owner?: string, + } export class TextChannel implements Channel { @@ -53,6 +55,12 @@ export class TextChannel implements Channel { */ @prop({ default: false }) rage_channel?: boolean; + + /** + * The queue to show activities of + */ + @prop({ ref: () => Queue }) + queue?: Ref; } export const TextChannelModel = getModelForClass(TextChannel, { diff --git a/src/utils/general.ts b/src/utils/general.ts index 7b19ff6..a2151be 100644 --- a/src/utils/general.ts +++ b/src/utils/general.ts @@ -1,24 +1,25 @@ import { ConfigHandler } from "./../handlers/configHandler"; import { DBRole, InternalRoles, RoleScopes } from "./../models/bot_roles"; import ChannelType, { - CommandInteraction, + CommandInteraction, Guild as DiscrodGuild, Guild, GuildMember, GuildMemberResolvable, GuildResolvable, Interaction, Message, - RoleResolvable, + RoleResolvable, TextChannel, User, UserResolvable } from "discord.js"; import moment from "moment"; import { Command, StringReplacements } from "../../typings"; -import { GuildModel } from "../models/guilds"; +import { Guild as GuildDB, GuildModel } from "../models/guilds"; import { Bot } from "../bot"; import { UserModel } from "../models/users"; import * as cryptojs from "crypto-js"; -import { DocumentType } from "@typegoose/typegoose"; +import {ArraySubDocumentType, DocumentType} from "@typegoose/typegoose"; +import {Queue} from "../models/queues"; /** * Checks if a given Variable is an array[] with at least a length of one or not @@ -427,4 +428,30 @@ export async function removeRoleFromUser(g: Guild, user: User, roleName: string) } else { console.error(`Could not remove role: ${roleName} from ${user.username} on guild: ${g.name}`) } +} + +/** +* assigns the waiting role and informs tutors that user has joined +* @param g +* @param guildData +* @param user +* @param queueData +*/ +export async function manageJoinQueue(g: DiscrodGuild, guildData: DocumentType, user: User, queueData: ArraySubDocumentType) { + const roles = await g.roles.fetch(); + const waiting_role = roles.find(role => role.name.toLowerCase() === queueData.name.toLowerCase() + "-waiting"); + + const member = g.members.resolve(user); + if (waiting_role && member && !member.roles.cache.has(waiting_role.id)) { + member.roles.add(waiting_role); + } + const channel = guildData.text_channels.find(channel => channel.queue?._id.toString() === queueData.id) + const activeSessionRole = guildData.guild_settings.roles?.find(role => role.internal_name === InternalRoles.ACTIVE_SESSION) + + if (channel && activeSessionRole) { + const discordChannel = await g.channels.fetch(channel.id) as TextChannel + await discordChannel.send(`<@&${activeSessionRole?.role_id}> ${user.displayName} joined the queue`) + } + + // await member?.voice.disconnect(); } \ No newline at end of file