From 573040362deb92d17e7f1b920996a4e641d2f2cc Mon Sep 17 00:00:00 2001 From: Yuzu Date: Mon, 6 Jun 2022 14:59:53 +0700 Subject: [PATCH] Formatted code and clean up --- src/discord/Core.ts | 34 +- src/discord/Help.ts | 47 +- src/discord/InteractionManager.ts | 125 +++--- src/discord/Invite.ts | 40 +- src/discord/MembershipScreening.ts | 444 ++++++++++++------- src/discord/Ping.ts | 135 +++--- src/discord/Say.ts | 88 ++-- src/discord/Settings.ts | 433 +++++++++++------- src/discord/Stats.ts | 46 +- src/discord/UserInfo.ts | 167 ++++--- src/discord/developer/Debug.ts | 132 +++--- src/discord/developer/ServiceAnnouncement.ts | 284 +++++++----- src/discord/osu.ts | 401 ++++++++++------- src/exception/Errors.ts | 18 +- src/exception/NativeException.ts | 13 +- src/index.ts | 2 +- src/libs/Logger.ts | 16 +- src/providers/App.ts | 12 +- src/providers/Cache.ts | 33 +- src/providers/Configuration.ts | 36 +- src/providers/Discord.ts | 282 +++++++----- src/providers/DiscordMusicPlayer.ts | 212 +++++---- src/providers/Environment.ts | 32 +- src/providers/Prisma.ts | 8 +- src/providers/osuAPI.ts | 9 +- src/services/Users.ts | 15 +- src/utils/DiscordInteraction.ts | 324 +++++++------- src/utils/DiscordMessage.ts | 272 ++++++++---- src/utils/DiscordModule.ts | 104 +++-- 29 files changed, 2208 insertions(+), 1556 deletions(-) diff --git a/src/discord/Core.ts b/src/discord/Core.ts index 08b2da2..9112e5b 100644 --- a/src/discord/Core.ts +++ b/src/discord/Core.ts @@ -1,19 +1,18 @@ -import DiscordModule from "../utils/DiscordModule"; +import { Guild } from 'discord.js'; -import { Guild } from "discord.js"; -import Logger from "../libs/Logger"; -import Cache from "../providers/Cache"; -import DiscordProvider from "../providers/Discord"; -import Prisma from "../providers/Prisma"; +import DiscordModule from '../utils/DiscordModule'; +import DiscordProvider from '../providers/Discord'; + +import Logger from '../libs/Logger'; +import Cache from '../providers/Cache'; +import Prisma from '../providers/Prisma'; export default class Core extends DiscordModule { - - public id: string = "Discord_Core"; + public id: string = 'Discord_Core'; async Ready() { - let data = []; - for(let Guild of DiscordProvider.client.guilds.cache.map(guild => guild)) { + for (let Guild of DiscordProvider.client.guilds.cache.map((guild) => guild)) { data.push({ id: Guild.id }); } @@ -25,20 +24,19 @@ export default class Core extends DiscordModule { await Cache.updateGuildsCache(); setInterval(() => { Cache.updateGuildsCache(); - }, 5 * 60 * 1000) + }, 5 * 60 * 1000); setInterval(() => { - DiscordProvider.client.user!.setActivity("for your heart ๐Ÿ’–", { - type: "COMPETING" + DiscordProvider.client.user!.setActivity('for your heart ๐Ÿ’–', { + type: 'COMPETING' }); - }, 5 * 60 * 1000) - + }, 5 * 60 * 1000); + Logger.info('Core started successfully'); - } - + async GuildCreate(guild: Guild) { - if(await Prisma.client.guild.findFirst({ where: {id: guild.id} })) return; + if (await Prisma.client.guild.findFirst({ where: { id: guild.id } })) return; await Prisma.client.guild.create({ data: { diff --git a/src/discord/Help.ts b/src/discord/Help.ts index 50baa34..7b1f184 100644 --- a/src/discord/Help.ts +++ b/src/discord/Help.ts @@ -1,25 +1,29 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; +import { CommandInteraction, Interaction, Message } from 'discord.js'; -import { CommandInteraction, Interaction, Message } from "discord.js"; -import { sendHybridInteractionMessageResponse, makeInfoEmbed } from "../utils/DiscordMessage"; -import DiscordProvider from "../providers/Discord"; -import Cache from "../providers/Cache"; +import DiscordProvider from '../providers/Discord'; +import Cache from '../providers/Cache'; + +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; +import { sendHybridInteractionMessageResponse, makeInfoEmbed } from '../utils/DiscordMessage'; const EMBEDS = { INFO: async (data: Message | Interaction) => { - let GuildCache = await Cache.getGuild(data.guildId!); // TODO: Better error handling - if(typeof GuildCache === 'undefined') - throw new Error("Guild not found"); + if (typeof GuildCache === 'undefined') throw new Error('Guild not found'); let prefix = GuildCache.prefix || '>'; let _e = makeInfoEmbed({ - icon: "๐Ÿ’Œ", + icon: '๐Ÿ’Œ', title: `Help - ${DiscordProvider.client.user?.username}`, - description: `\u200b\n๐Ÿ“ฐโ€‚**Info**\nYumi is currently undergoing complete rewrite, as expected, losing many of her functionality. All of the features will be re-implemented.\n\n๐Ÿท๏ธโ€‚**Prefix**\nYou can call me using \`\`${prefix.replaceAll('`','`โ€‹')}\`\`, <@${DiscordProvider.client.user?.id}> or \`\`/slash command\`\`\n\n๐Ÿ’ปโ€‚**Available commands**`, + description: `\u200b\n๐Ÿ“ฐโ€‚**Info**\nYumi is currently undergoing complete rewrite, as expected, losing many of her functionality. All of the features will be re-implemented.\n\n๐Ÿท๏ธโ€‚**Prefix**\nYou can call me using \`\`${prefix.replaceAll( + '`', + '`โ€‹' + )}\`\`, <@${ + DiscordProvider.client.user?.id + }> or \`\`/slash command\`\`\n\n๐Ÿ’ปโ€‚**Available commands**`, fields: [ { name: 'โ˜•โ€‚General', @@ -52,31 +56,32 @@ const EMBEDS = { inline: false } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); _e.setThumbnail(`${DiscordProvider.client.user?.displayAvatarURL()}?size=4096`); return _e; } -} +}; export default class Help extends DiscordModule { - - public id = "Discord_Help"; - public commands = ["help"]; - public commandInteractionName = "help"; + public id = 'Discord_Help'; + public commands = ['help']; + public commandInteractionName = 'help'; async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { - const message = await sendHybridInteractionMessageResponse(data, { embeds: [await EMBEDS.INFO(data.getRaw())] }); + const message = await sendHybridInteractionMessageResponse(data, { + embeds: [await EMBEDS.INFO(data.getRaw())] + }); - if(message && data.isMessage()) - return new HybridInteractionMessage(message).getMessage().react("โ™ฅ"); + if (message && data.isMessage()) + return new HybridInteractionMessage(message).getMessage().react('โ™ฅ'); } -} \ No newline at end of file +} diff --git a/src/discord/InteractionManager.ts b/src/discord/InteractionManager.ts index aecc89b..b0a7383 100644 --- a/src/discord/InteractionManager.ts +++ b/src/discord/InteractionManager.ts @@ -1,9 +1,19 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; +import { Message, Interaction, CommandInteraction } from 'discord.js'; -import { Message, Interaction, CommandInteraction } from "discord.js"; -import { makeInfoEmbed, makeErrorEmbed, makeSuccessEmbed, makeProcessingEmbed, sendHybridInteractionMessageResponse } from "../utils/DiscordMessage"; -import {registerAllGuildsCommands, unregisterAllGuildsCommands} from "../utils/DiscordInteraction"; -import Users from "../services/Users"; +import Users from '../services/Users'; + +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; +import { + makeInfoEmbed, + makeErrorEmbed, + makeSuccessEmbed, + makeProcessingEmbed, + sendHybridInteractionMessageResponse +} from '../utils/DiscordMessage'; +import { + registerAllGuildsCommands, + unregisterAllGuildsCommands +} from '../utils/DiscordInteraction'; const EMBEDS = { INTERACTION_INFO: (data: Message | Interaction) => { @@ -16,105 +26,118 @@ const EMBEDS = { value: '``reloadAll``' } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, PROCESSING: (data: Message | Interaction) => { return makeProcessingEmbed({ - icon: (data instanceof Message) ? undefined : 'โŒ›', + icon: data instanceof Message ? undefined : 'โŒ›', title: `Performing actions`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NOT_DEVELOPER: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'Developer only', description: `This command is restricted to the developers only`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, RELOADALL_SUCCESS: (data: Message | Interaction) => { return makeSuccessEmbed({ title: 'Reloaded all Interaction', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, RELOADALL_ERROR: (data: Message | Interaction, err: any) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'An error occurred while trying to reload interaction', description: '```' + err + '```', - user: (data instanceof Interaction) ? data.user : data.author - }) + user: data instanceof Interaction ? data.user : data.author + }); } -} +}; export default class InteractionManager extends DiscordModule { - - public id = "Discord_InteractionManager"; - public commands = ["interaction"]; - public commandInteractionName = "interaction"; + public id = 'Discord_InteractionManager'; + public commands = ['interaction']; + public commandInteractionName = 'interaction'; async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { - const user = data.getUser(); - if(!user) return; + if (!user) return; - if(!Users.isDeveloper(user.id)) - return await sendHybridInteractionMessageResponse(data, { embeds:[EMBEDS.NOT_DEVELOPER(data.getRaw())] }); + if (!Users.isDeveloper(user.id)) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NOT_DEVELOPER(data.getRaw())] + }); const funct = { - reloadAll: async(data: HybridInteractionMessage) => { + reloadAll: async (data: HybridInteractionMessage) => { + let placeholder: HybridInteractionMessage | undefined; - let placeholder: (HybridInteractionMessage | undefined); - - let _placeholder = await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PROCESSING(data.getRaw())] }); - if (_placeholder) - placeholder = new HybridInteractionMessage(_placeholder); + let _placeholder = await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.PROCESSING(data.getRaw())] + }); + if (_placeholder) placeholder = new HybridInteractionMessage(_placeholder); try { await unregisterAllGuildsCommands(); await registerAllGuildsCommands(); - if(data && data.isMessage() && placeholder && placeholder.isMessage()) - return placeholder.getMessage().edit({ embeds: [EMBEDS.RELOADALL_SUCCESS(data.getRaw())] }); - else if(data.isSlashCommand()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.RELOADALL_SUCCESS(data.getRaw())]}, true); - + if (data && data.isMessage() && placeholder && placeholder.isMessage()) + return placeholder + .getMessage() + .edit({ embeds: [EMBEDS.RELOADALL_SUCCESS(data.getRaw())] }); + else if (data.isSlashCommand()) + return await sendHybridInteractionMessageResponse( + data, + { embeds: [EMBEDS.RELOADALL_SUCCESS(data.getRaw())] }, + true + ); } catch (err) { - if(data && data.isMessage() && placeholder && placeholder.isMessage()) - return placeholder.getMessage().edit({ embeds: [EMBEDS.RELOADALL_ERROR(data.getRaw(), err)] }); - else if(data.isSlashCommand()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.RELOADALL_ERROR(data.getRaw(), err)] }, true); - } + if (data && data.isMessage() && placeholder && placeholder.isMessage()) + return placeholder + .getMessage() + .edit({ embeds: [EMBEDS.RELOADALL_ERROR(data.getRaw(), err)] }); + else if (data.isSlashCommand()) + return await sendHybridInteractionMessageResponse( + data, + { embeds: [EMBEDS.RELOADALL_ERROR(data.getRaw(), err)] }, + true + ); + } } - } + }; let query; - if(data.isMessage()) { - if(args.length === 0) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INTERACTION_INFO(data.getRaw())] }); + if (data.isMessage()) { + if (args.length === 0) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INTERACTION_INFO(data.getRaw())] + }); query = args[0].toLowerCase(); - } - else if(data.isSlashCommand()) { + } else if (data.isSlashCommand()) { query = args.getSubcommand(); } - switch(query) { - case "info": - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INTERACTION_INFO(data.getRaw())] }); - case "reloadall": + switch (query) { + case 'info': + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INTERACTION_INFO(data.getRaw())] + }); + case 'reloadall': return await funct.reloadAll(data); } - } -} \ No newline at end of file +} diff --git a/src/discord/Invite.ts b/src/discord/Invite.ts index 2a93f9c..a18a316 100644 --- a/src/discord/Invite.ts +++ b/src/discord/Invite.ts @@ -1,40 +1,44 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; +import { Message, CommandInteraction, Interaction } from 'discord.js'; -import { Message, CommandInteraction, Interaction } from "discord.js"; -import { sendHybridInteractionMessageResponse, makeInfoEmbed } from "../utils/DiscordMessage"; -import DiscordProvider from "../providers/Discord"; -import Users from "../services/Users" -import Environment from "../providers/Environment"; +import Environment from '../providers/Environment'; +import DiscordProvider from '../providers/Discord'; +import Users from '../services/Users'; + +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; +import { sendHybridInteractionMessageResponse, makeInfoEmbed } from '../utils/DiscordMessage'; const EMBEDS = { INVITE_INFO: (data: Message | Interaction) => { let message; - if(Users.isDeveloper(data.member?.user.id!) || !Environment.get().PRIVATE_BOT) + if (Users.isDeveloper(data.member?.user.id!) || !Environment.get().PRIVATE_BOT) message = `[Invite ${DiscordProvider.client.user?.username} to your server!](https://discord.com/api/oauth2/authorize?client_id=${DiscordProvider.client.user?.id}&permissions=0&scope=bot%20applications.commands)`; - + return makeInfoEmbed({ title: `Invite`, - description: message || `${DiscordProvider.client.user?.username}'s invite is currently private. Only the developers can add me to another server`, - user: (data instanceof Interaction) ? data.user : data.author + description: + message || + `${DiscordProvider.client.user?.username}'s invite is currently private. Only the developers can add me to another server`, + user: data instanceof Interaction ? data.user : data.author }); } -} +}; export default class Invite extends DiscordModule { + public id: string = 'Discord_Invite'; + public commands = ['invite']; + public commandInteractionName = 'invite'; - public id: string = "Discord_Invite"; - public commands = ["invite"]; - public commandInteractionName = "invite"; - async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { - return await sendHybridInteractionMessageResponse(data, { embeds:[EMBEDS.INVITE_INFO(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INVITE_INFO(data.getRaw())] + }); } -} \ No newline at end of file +} diff --git a/src/discord/MembershipScreening.ts b/src/discord/MembershipScreening.ts index 3417659..03aaa00 100644 --- a/src/discord/MembershipScreening.ts +++ b/src/discord/MembershipScreening.ts @@ -1,47 +1,67 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; +import App from '..'; +import { + GuildChannel, + GuildMember, + Message, + Permissions, + TextChannel, + MessageActionRow, + MessageButton, + Interaction, + CommandInteraction, + Role, + ThreadChannel, + ButtonInteraction +} from 'discord.js'; -import { GuildChannel, GuildMember, Message, Permissions, TextChannel, MessageActionRow, MessageButton, Interaction, CommandInteraction, Role, ThreadChannel, ButtonInteraction } from "discord.js"; -import App from ".."; -import { makeSuccessEmbed, makeInfoEmbed, makeErrorEmbed, sendHybridInteractionMessageResponse, sendMessage } from "../utils/DiscordMessage"; -import DiscordProvider from "../providers/Discord"; -import Prisma from "../providers/Prisma"; +import DiscordProvider from '../providers/Discord'; +import Prisma from '../providers/Prisma'; + +import { + makeSuccessEmbed, + makeInfoEmbed, + makeErrorEmbed, + sendHybridInteractionMessageResponse, + sendMessage +} from '../utils/DiscordMessage'; +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; const EMBEDS = { NO_PERMISSION: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'You need ``ADMINISTRATOR`` permission on this guild!', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_PARAMETER: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'Missing parameter', description: `You must define membership screening channel and role to enable this feature`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_ROLE_MENTIONED: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'No role mentioned', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_ROLE_FOUND: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'Cannot find that role', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_CHANNEL_MENTIONED: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'No channel mentioned', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_CHANNEL_FOUND: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'Cannot find that channel', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, MSINFO: (data: Message | Interaction) => { @@ -54,106 +74,120 @@ const EMBEDS = { value: '``setRole`` ``setChannel`` ``createMessage``' } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, ALREADY_ENABLED: (data: Message | Interaction) => { return makeInfoEmbed({ title: 'Membership Screening is already enabled', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, MESSAGE_CREATED: (data: Message | Interaction) => { return makeSuccessEmbed({ title: 'Membership Screening message created', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, ALREADY_DISABLED: (data: Message | Interaction) => { return makeInfoEmbed({ title: 'Membership Screening is already disabled', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, ENABLED: (data: Message | Interaction) => { return makeSuccessEmbed({ title: 'Enabled Membership Screening', description: `All new member join request will be sent in your defined channel`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, DISABLED: (data: Message | Interaction) => { return makeSuccessEmbed({ title: 'Disabled Membership Screening', description: `No longer accepting request, all new member can join directly`, - user: (data instanceof Interaction) ? data.user : data.author - }) + user: data instanceof Interaction ? data.user : data.author + }); }, MANAGED_ROLE: (data: Message | Interaction, role: Role) => { return makeErrorEmbed({ title: 'You cannot use this role', - description: '``' + role.name + '``' + ' is managed by external service and cannot be used', - user: (data instanceof Interaction) ? data.user : data.author + description: + '``' + role.name + '``' + ' is managed by external service and cannot be used', + user: data instanceof Interaction ? data.user : data.author }); }, CONFIGURED_ROLE: (data: Message | Interaction, role: Role) => { return makeSuccessEmbed({ title: 'Configured Membership Screening Role', - description: 'New member will be given a ' + '``' + role.name + '``' + ' role after approval', - user: (data instanceof Interaction) ? data.user : data.author + description: + 'New member will be given a ' + '``' + role.name + '``' + ' role after approval', + user: data instanceof Interaction ? data.user : data.author }); }, CONFIGURED_CHANNEL: (data: Message | Interaction, channel: GuildChannel) => { return makeSuccessEmbed({ title: 'Configured Membership Screening Channel', - description: 'Anyone with ``VIEW_CHANNEL`` permission in ' + '``' + channel.name + '``' + ' can approve or deny request', - user: (data instanceof Interaction) ? data.user : data.author + description: + 'Anyone with ``VIEW_CHANNEL`` permission in ' + + '``' + + channel.name + + '``' + + ' can approve or deny request', + user: data instanceof Interaction ? data.user : data.author }); }, INVALID_CHANNEL: (data: Message | Interaction, channel: GuildChannel) => { return makeErrorEmbed({ title: 'Invalid channel type, only TextChannel is supported', description: '``' + channel.name + '``' + ' is not a text channel', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, - INVALID_CHANNEL_THREAD: (data: Message | Interaction, channel: GuildChannel | ThreadChannel) => { + INVALID_CHANNEL_THREAD: ( + data: Message | Interaction, + channel: GuildChannel | ThreadChannel + ) => { return makeErrorEmbed({ title: 'Thread channel is not supported', - description: '``' + channel.name + '``' + ' is a thread channel. Please use a regular text channel', - user: (data instanceof Interaction) ? data.user : data.author + description: + '``' + + channel.name + + '``' + + ' is a thread channel. Please use a regular text channel', + user: data instanceof Interaction ? data.user : data.author }); }, BOT_NO_PERMISSION: (data: Message | Interaction, channel: GuildChannel) => { return makeErrorEmbed({ title: `I don't have permission`, description: 'I cannot access/send message in ' + '``' + channel.name + '``', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_LONGER_VALID_ROLE: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'The configured role is no longer valid. Please update the role in configuration', - user: (data instanceof Interaction) ? data.user : data.author - }) + user: data instanceof Interaction ? data.user : data.author + }); }, CANNOT_PERFORM_ASSIGN_ROLE: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'Cannot grant the role to user, make sure I have permission to do that', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, CANNOT_PERFORM_ASSIGN_KICK: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'Cannot kick the user, make sure I have permission to do that', - user: (data instanceof Interaction) ? data.user : data.author - }) + user: data instanceof Interaction ? data.user : data.author + }); }, CANNOT_PERFORM_ASSIGN_BAN: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'Cannot ban the user, make sure I have permission to do that', - user: (data instanceof Interaction) ? data.user : data.author - }) + user: data instanceof Interaction ? data.user : data.author + }); }, CREATE_MESSAGE: () => { return makeInfoEmbed({ @@ -161,15 +195,14 @@ const EMBEDS = { title: 'Welcome to this server!', description: `This server have membership screening enabled, **you'll have access to the server when the moderators let you in**.\n\nAlso please make sure that you acknowledged the common rules that everyone should be doing no matter where, Discord ToS (https://discordapp.com/terms)`, user: DiscordProvider.client.user - }) + }); } -} +}; export default class MembershipScreening extends DiscordModule { - - public id = "Discord_MembershipScreening"; - public commands = ["membershipscreening", "ms"]; - public commandInteractionName = "membershipscreening"; + public id = 'Discord_MembershipScreening'; + public commands = ['membershipscreening', 'ms']; + public commandInteractionName = 'membershipscreening'; async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); @@ -180,20 +213,22 @@ export default class MembershipScreening extends DiscordModule { } async GuildButtonInteractionCreate(interaction: ButtonInteraction) { - const hybridData = new HybridInteractionMessage(interaction); const guild = hybridData.getGuild(); const user = hybridData.getUser(); const channel = hybridData.getChannel(); - if(!guild || !user || !channel) return; + if (!guild || !user || !channel) return; if (!this.isJsonValid(interaction.customId)) return; const payload = JSON.parse(interaction.customId); - if (typeof payload.m === 'undefined' || + if ( + typeof payload.m === 'undefined' || typeof payload.a === 'undefined' || - payload.m !== 'MembershipScreening') return; + payload.m !== 'MembershipScreening' + ) + return; const message = await channel.messages.fetch(interaction.message.id); if (!message) return; @@ -204,75 +239,96 @@ export default class MembershipScreening extends DiscordModule { const PrismaGuild = await Prisma.client.guild.findFirst({ where: { id: guild.id } }); if (!PrismaGuild) return; - if (!PrismaGuild.MembershipScreening_Enabled || + if ( + !PrismaGuild.MembershipScreening_Enabled || PrismaGuild.MembershipScreening_ApprovalChannel === null || - PrismaGuild.MembershipScreening_GivenRole === null) return; + PrismaGuild.MembershipScreening_GivenRole === null + ) + return; embed[0].footer = { text: `${interaction.user.username} | v${App.version}`, iconURL: `${interaction.user.displayAvatarURL()}?size=4096` - } + }; if (['approve', 'deny', 'ban'].includes(payload.a)) { - if (!payload.d.requester) return; - const role = (await guild.roles.fetch()).find(role => role.id === PrismaGuild.MembershipScreening_GivenRole); - const requesterMember = (await guild.members.fetch()).find(member => member.id === payload.d.requester); + const role = (await guild.roles.fetch()).find( + (role) => role.id === PrismaGuild.MembershipScreening_GivenRole + ); + const requesterMember = (await guild.members.fetch()).find( + (member) => member.id === payload.d.requester + ); if (!role) - return await interaction.reply({ ephemeral: true, embeds: [EMBEDS.NO_LONGER_VALID_ROLE(interaction)] }); + return await interaction.reply({ + ephemeral: true, + embeds: [EMBEDS.NO_LONGER_VALID_ROLE(interaction)] + }); if (!requesterMember) { - embed[0].addField("โŒ Invalid", `Unable to find the user. User left already?`); + embed[0].addField('โŒ Invalid', `Unable to find the user. User left already?`); return await message.edit({ components: [], embeds: embed }); } if (requesterMember.roles.cache.has(PrismaGuild.MembershipScreening_GivenRole)) { - embed[0].addField("โœ… Approved", `By: Unknown (User already obtained the role by other means)`); + embed[0].addField( + 'โœ… Approved', + `By: Unknown (User already obtained the role by other means)` + ); return await message.edit({ components: [], embeds: embed }); } if (payload.a === 'approve') { try { await requesterMember.roles.add(role); - embed[0].addField("โœ… Approved", `By: ${interaction.user.username}#${interaction.user.discriminator} (${interaction.user.id})`); + embed[0].addField( + 'โœ… Approved', + `By: ${interaction.user.username}#${interaction.user.discriminator} (${interaction.user.id})` + ); await message.edit({ components: [], embeds: embed }); + } catch (err) { + return interaction.reply({ + ephemeral: true, + embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_ROLE(message)] + }); } - catch (err) { - return interaction.reply({ ephemeral: true, embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_ROLE(message)] }); - } - } - - else if (payload.a === 'deny') { + } else if (payload.a === 'deny') { try { await requesterMember.kick(); - embed[0].addField("โŒ Denied", `By: ${interaction.user.username}#${interaction.user.discriminator} (${interaction.user.id})`); + embed[0].addField( + 'โŒ Denied', + `By: ${interaction.user.username}#${interaction.user.discriminator} (${interaction.user.id})` + ); await message.edit({ components: [], embeds: embed }); + } catch (err) { + return interaction.reply({ + ephemeral: true, + embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_KICK(message)] + }); } - catch (err) { - return interaction.reply({ ephemeral: true, embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_KICK(message)] }); - } - } - - else if (payload.a === 'ban') { + } else if (payload.a === 'ban') { try { await requesterMember.ban({ reason: `Membership Screening, action issued by ${interaction.user.username}#${interaction.user.discriminator} (${interaction.user.id})` }); - embed[0].addField("๐Ÿ”ช Banned", `By: ${interaction.user.username}#${interaction.user.discriminator} (${interaction.user.id})`); + embed[0].addField( + '๐Ÿ”ช Banned', + `By: ${interaction.user.username}#${interaction.user.discriminator} (${interaction.user.id})` + ); await message.edit({ components: [], embeds: embed }); - } - catch (err) { - return interaction.reply({ ephemeral: true, embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_BAN(message)] }); + } catch (err) { + return interaction.reply({ + ephemeral: true, + embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_BAN(message)] + }); } } - } } async run(data: HybridInteractionMessage, args: any) { - const guild = data.getGuild(); const user = data.getUser(); const member = data.getMember(); @@ -280,24 +336,32 @@ export default class MembershipScreening extends DiscordModule { if (!guild || !user || !member || !channel) return; - const PrismaGuild = await Prisma.client.guild.findFirst({ where: { id: guild.id } }) + const PrismaGuild = await Prisma.client.guild.findFirst({ where: { id: guild.id } }); if (!PrismaGuild) return; - const funct = { enable: async (data: HybridInteractionMessage) => { if (!PrismaGuild.MembershipScreening_Enabled) { + if ( + PrismaGuild.MembershipScreening_GivenRole === null || + PrismaGuild.MembershipScreening_ApprovalChannel == null + ) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_PARAMETER(data.getRaw())] + }); - if (PrismaGuild.MembershipScreening_GivenRole === null || PrismaGuild.MembershipScreening_ApprovalChannel == null) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PARAMETER(data.getRaw())] }); + await Prisma.client.guild.update({ + where: { id: guild.id }, + data: { MembershipScreening_Enabled: true } + }); - await Prisma.client.guild.update({ where: { id: guild.id }, data: { MembershipScreening_Enabled: true } }); - - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ENABLED(data.getRaw())] }); - } - - else - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ALREADY_ENABLED(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.ENABLED(data.getRaw())] + }); + } else + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.ALREADY_ENABLED(data.getRaw())] + }); }, disable: async (data: HybridInteractionMessage) => { if (PrismaGuild.MembershipScreening_Enabled) { @@ -306,111 +370,150 @@ export default class MembershipScreening extends DiscordModule { data: { MembershipScreening_Enabled: false } }); - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.DISABLED(data.getRaw())] }); - } - else - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ALREADY_DISABLED(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.DISABLED(data.getRaw())] + }); + } else + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.ALREADY_DISABLED(data.getRaw())] + }); }, setRole: async (data: HybridInteractionMessage) => { - let role: Role | undefined; if (data.isMessage()) { let _name: string; if (typeof args[1] === 'undefined') - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_ROLE_MENTIONED(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_ROLE_MENTIONED(data.getRaw())] + }); let __name = args; __name.shift(); - _name = __name.join(" "); + _name = __name.join(' '); - role = data.getMessage().mentions.roles.first() || guild.roles.cache.find(role => role.name === _name); - } - else if (data.isSlashCommand()) - role = guild.roles.cache.find(role => role.id === data.getSlashCommand().options.getRole('role')?.id); + role = + data.getMessage().mentions.roles.first() || + guild.roles.cache.find((role) => role.name === _name); + } else if (data.isSlashCommand()) + role = guild.roles.cache.find( + (role) => role.id === data.getSlashCommand().options.getRole('role')?.id + ); if (!role) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_ROLE_FOUND(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_ROLE_FOUND(data.getRaw())] + }); if (role.managed) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.MANAGED_ROLE(data.getRaw(), role)] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.MANAGED_ROLE(data.getRaw(), role)] + }); - await Prisma.client.guild.update({ where: { id: guild.id }, data: { MembershipScreening_GivenRole: role.id } }); + await Prisma.client.guild.update({ + where: { id: guild.id }, + data: { MembershipScreening_GivenRole: role.id } + }); - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.CONFIGURED_ROLE(data.getRaw(), role)] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.CONFIGURED_ROLE(data.getRaw(), role)] + }); }, setChannel: async (data: HybridInteractionMessage) => { - let mentionChannel; if (data.isMessage()) { if (!args[1]) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_CHANNEL_MENTIONED(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_CHANNEL_MENTIONED(data.getRaw())] + }); mentionChannel = data.getMessage().mentions.channels.first(); - } - else if (data.isSlashCommand()) + } else if (data.isSlashCommand()) mentionChannel = data.getSlashCommand().options.getChannel('channel'); if (!mentionChannel) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_CHANNEL_FOUND(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_CHANNEL_FOUND(data.getRaw())] + }); let TargetChannel = guild.channels.cache.get(mentionChannel.id); if (!TargetChannel) return; if (TargetChannel instanceof ThreadChannel || TargetChannel.isThread()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_CHANNEL_THREAD(data.getRaw(), TargetChannel)] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INVALID_CHANNEL_THREAD(data.getRaw(), TargetChannel)] + }); if (!TargetChannel.isText()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_CHANNEL(data.getRaw(), TargetChannel)] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INVALID_CHANNEL(data.getRaw(), TargetChannel)] + }); - if (!(guild.me!.permissionsIn(TargetChannel).has([Permissions.FLAGS.SEND_MESSAGES, Permissions.FLAGS.VIEW_CHANNEL]))) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.BOT_NO_PERMISSION(data.getRaw(), TargetChannel)] }); + if ( + !guild + .me!.permissionsIn(TargetChannel) + .has([Permissions.FLAGS.SEND_MESSAGES, Permissions.FLAGS.VIEW_CHANNEL]) + ) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.BOT_NO_PERMISSION(data.getRaw(), TargetChannel)] + }); - await Prisma.client.guild.update({ where: { id: guild.id }, data: { MembershipScreening_ApprovalChannel: mentionChannel.id } }); - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.CONFIGURED_CHANNEL(data.getRaw(), TargetChannel)] }); + await Prisma.client.guild.update({ + where: { id: guild.id }, + data: { MembershipScreening_ApprovalChannel: mentionChannel.id } + }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.CONFIGURED_CHANNEL(data.getRaw(), TargetChannel)] + }); }, createMessage: async (data: HybridInteractionMessage) => { - if(data.isMessage()) - return await sendMessage(channel, undefined, { embeds: [EMBEDS.CREATE_MESSAGE()] }); - else if(data.isSlashCommand()) { - await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.MESSAGE_CREATED(data.getRaw())] }); - return await sendMessage(channel, undefined, { embeds: [EMBEDS.CREATE_MESSAGE()] }); + if (data.isMessage()) + return await sendMessage(channel, undefined, { + embeds: [EMBEDS.CREATE_MESSAGE()] + }); + else if (data.isSlashCommand()) { + await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.MESSAGE_CREATED(data.getRaw())] + }); + return await sendMessage(channel, undefined, { + embeds: [EMBEDS.CREATE_MESSAGE()] + }); } } - } + }; let query; if (!member.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] + }); if (data.isMessage()) { if (args.length === 0) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.MSINFO(data.getRaw())] }); - + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.MSINFO(data.getRaw())] + }); + query = args[0].toLowerCase(); - } - else if (data.isSlashCommand()) - query = args.getSubcommand(); + } else if (data.isSlashCommand()) query = args.getSubcommand(); switch (query) { - case "enable": - case "on": + case 'enable': + case 'on': return await funct.enable(data); - case "disable": - case "off": + case 'disable': + case 'off': return await funct.disable(data); - case "setrole": + case 'setrole': return await funct.setRole(data); - case "setchannel": + case 'setchannel': return await funct.setChannel(data); - case "createmessage": + case 'createmessage': return await funct.createMessage(data); } - } async GuildMemberAdd(member: GuildMember) { - if (member.user.bot) return; const Guild = await Prisma.client.guild.findFirst({ where: { id: member.guild.id } }); @@ -422,7 +525,9 @@ export default class MembershipScreening extends DiscordModule { let channel = undefined; try { - channel = await DiscordProvider.client.channels.fetch(Guild.MembershipScreening_ApprovalChannel) as TextChannel; + channel = (await DiscordProvider.client.channels.fetch( + Guild.MembershipScreening_ApprovalChannel + )) as TextChannel; } catch (err) { // TODO: Handle channel not found error return; @@ -434,8 +539,10 @@ export default class MembershipScreening extends DiscordModule { description: `${member.user.username}#${member.user.discriminator} (${member.user.id})`, fields: [ { - name: "Account Information", - value: `Account age: ` + name: 'Account Information', + value: `Account age: ` } ] }); @@ -445,43 +552,49 @@ export default class MembershipScreening extends DiscordModule { const row = new MessageActionRow() .addComponents( new MessageButton() - .setCustomId(JSON.stringify({ - m: 'MembershipScreening', - a: 'approve', - d: { - requester: member.id - } - })) + .setCustomId( + JSON.stringify({ + m: 'MembershipScreening', + a: 'approve', + d: { + requester: member.id + } + }) + ) .setEmoji('โœ…') .setLabel(' Approve') - .setStyle('SUCCESS'), + .setStyle('SUCCESS') ) .addComponents( new MessageButton() - .setCustomId(JSON.stringify({ - m: 'MembershipScreening', - a: 'deny', - d: { - requester: member.id - } - })) + .setCustomId( + JSON.stringify({ + m: 'MembershipScreening', + a: 'deny', + d: { + requester: member.id + } + }) + ) .setEmoji('โ›”') .setLabel(' Deny and kick') - .setStyle('DANGER'), + .setStyle('DANGER') ) .addComponents( new MessageButton() - .setCustomId(JSON.stringify({ - m: 'MembershipScreening', - a: 'ban', - d: { - requester: member.id - } - })) + .setCustomId( + JSON.stringify({ + m: 'MembershipScreening', + a: 'ban', + d: { + requester: member.id + } + }) + ) .setEmoji('๐Ÿ”ช') .setLabel(' Vision Hunt Decree (Ban)') - .setStyle('DANGER'), - ) + .setStyle('DANGER') + ); await channel.send({ content: '\u200b', embeds: [embed], components: [row] }); } @@ -489,13 +602,12 @@ export default class MembershipScreening extends DiscordModule { private isJsonValid(jsonString: string) { try { let o = JSON.parse(jsonString); - if (o && typeof o === "object") { + if (o && typeof o === 'object') { return true; //return o; } - } - catch (e) { } + } catch (e) {} return false; } -} \ No newline at end of file +} diff --git a/src/discord/Ping.ts b/src/discord/Ping.ts index ea1ad73..3bc5c37 100644 --- a/src/discord/Ping.ts +++ b/src/discord/Ping.ts @@ -1,19 +1,23 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; +import { CommandInteraction, Message, Interaction } from 'discord.js'; +import os from 'os'; +import NodePing from 'ping'; +import { Promise } from 'bluebird'; -import { CommandInteraction, Message, Interaction } from "discord.js"; -import { makeSuccessEmbed, makeProcessingEmbed, sendHybridInteractionMessageResponse } from "../utils/DiscordMessage"; +import Configuration from '../providers/Configuration'; +import DiscordProvider from '../providers/Discord'; +import Environment from '../providers/Environment'; -import DiscordProvider from "../providers/Discord"; -import NodePing from "ping"; -import { Promise } from "bluebird"; -import os from "os"; -import Environment from "../providers/Environment"; -import Configuration from "../providers/Configuration"; +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; +import { + makeSuccessEmbed, + makeProcessingEmbed, + sendHybridInteractionMessageResponse +} from '../utils/DiscordMessage'; enum MeasureType { - Ping = "ping", - DiscordHTTPPing = "discordhttp", - DiscordWebsocket = "discordwebsocket" + Ping = 'ping', + DiscordHTTPPing = 'discordhttp', + DiscordWebsocket = 'discordwebsocket' } const EMBEDS = { @@ -22,23 +26,22 @@ const EMBEDS = { icon: '๐ŸŒŽ', title: `Network performance`, description: description, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, PINGING: (data: HybridInteractionMessage) => { return makeProcessingEmbed({ icon: data.isMessage() ? undefined : 'โŒ›', title: `Measuring network performance`, - user: (data.isInteraction()) ? data.getInteraction().user : data.getMessage().author + user: data.isInteraction() ? data.getInteraction().user : data.getMessage().author }); } -} +}; export default class Ping extends DiscordModule { - - public id = "Discord_Ping"; - public commands = ["ping"]; - public commandInteractionName = "ping"; + public id = 'Discord_Ping'; + public commands = ['ping']; + public commandInteractionName = 'ping'; async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); @@ -49,57 +52,77 @@ export default class Ping extends DiscordModule { } async run(data: HybridInteractionMessage, args: any) { - let placeholder: (HybridInteractionMessage | undefined); + let placeholder: HybridInteractionMessage | undefined; let beforeEditDate = Date.now(); - let _placeholder = await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PINGING(data)] }); - if (_placeholder) - placeholder = new HybridInteractionMessage(_placeholder); + let _placeholder = await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.PINGING(data)] + }); + if (_placeholder) placeholder = new HybridInteractionMessage(_placeholder); let afterEditDate = Date.now(); - let finalString = []; - await Promise.map(Configuration.getConfig("Ping"), (entry: any) => { - return new Promise(async (resolve, reject) => { - let stringCurrent = `${entry.title}`; + await Promise.map( + Configuration.getConfig('Ping'), + (entry: any) => { + return new Promise(async (resolve, reject) => { + let stringCurrent = `${entry.title}`; - if (entry.type === MeasureType.Ping) { - const res = await NodePing.promise.probe(entry.host!, { min_reply: 4 }); + if (entry.type === MeasureType.Ping) { + const res = await NodePing.promise.probe(entry.host!, { min_reply: 4 }); - if (!res.alive) { - stringCurrent += "Failed"; - return finalString.push(stringCurrent); + if (!res.alive) { + stringCurrent += 'Failed'; + return finalString.push(stringCurrent); + } + + if ( + res.avg === 'unknown' || + res.min === 'unknown' || + res.max === 'unknown' + ) { + stringCurrent += 'Failed'; + return finalString.push(stringCurrent); + } + + stringCurrent += `${parseFloat(res.avg).toFixed(1)}ms (${parseFloat( + res.min + ).toFixed(1)}ms - ${parseFloat(res.max).toFixed(1)}ms)`; + finalString.push(stringCurrent); + } else if (entry.type === MeasureType.DiscordWebsocket) { + stringCurrent += `${Math.round(DiscordProvider.client.ws.ping).toFixed( + 1 + )}ms`; + finalString.push(stringCurrent); + } else if (entry.type === MeasureType.DiscordHTTPPing) { + stringCurrent += `${Math.abs(afterEditDate - beforeEditDate).toFixed(1)}ms`; + finalString.push(stringCurrent); } - if (res.avg === 'unknown' || res.min === 'unknown' || res.max === 'unknown') { - stringCurrent += "Failed"; - return finalString.push(stringCurrent); - } + resolve(); + }); + }, + { concurrency: 5 } + ); - stringCurrent += `${parseFloat(res.avg).toFixed(1)}ms (${parseFloat(res.min).toFixed(1)}ms - ${parseFloat(res.max).toFixed(1)}ms)`; - finalString.push(stringCurrent); - } else if (entry.type === MeasureType.DiscordWebsocket) { - stringCurrent += `${Math.round(DiscordProvider.client.ws.ping).toFixed(1)}ms`; - finalString.push(stringCurrent); - } else if (entry.type === MeasureType.DiscordHTTPPing) { - stringCurrent += `${Math.abs(afterEditDate - beforeEditDate).toFixed(1)}ms`; - finalString.push(stringCurrent); - } - - resolve(); - }); - }, { concurrency: 5 }); - - finalString.push(""); - finalString.push("๐Ÿ’ปโ€‚Running on " + `${os.hostname()}${Environment.get().NODE_ENV === "development" ? ' / Development Environment' : ''}`); + finalString.push(''); + finalString.push( + '๐Ÿ’ปโ€‚Running on ' + + `${os.hostname()}${ + Environment.get().NODE_ENV === 'development' ? ' / Development Environment' : '' + }` + ); if (data.isSlashCommand()) - return await data.getMessageComponentInteraction().editReply({ embeds: [EMBEDS.PING_INFO(data.getRaw(), finalString.join('\n'))] }); + return await data + .getMessageComponentInteraction() + .editReply({ embeds: [EMBEDS.PING_INFO(data.getRaw(), finalString.join('\n'))] }); else if (data && data.isMessage() && placeholder && placeholder.isMessage()) - return await placeholder.getMessage().edit({ embeds: [EMBEDS.PING_INFO(data.getRaw(), finalString.join('\n'))] }); + return await placeholder + .getMessage() + .edit({ embeds: [EMBEDS.PING_INFO(data.getRaw(), finalString.join('\n'))] }); } - -} \ No newline at end of file +} diff --git a/src/discord/Say.ts b/src/discord/Say.ts index 067f7cf..700e821 100644 --- a/src/discord/Say.ts +++ b/src/discord/Say.ts @@ -1,11 +1,16 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; +import { Message, Permissions, Interaction, CommandInteraction } from 'discord.js'; -import { Message, Permissions, Interaction, CommandInteraction } from "discord.js"; -import { makeSuccessEmbed, sendHybridInteractionMessageResponse, makeErrorEmbed, makeInfoEmbed } from "../utils/DiscordMessage"; +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; +import { + makeSuccessEmbed, + sendHybridInteractionMessageResponse, + makeErrorEmbed, + makeInfoEmbed +} from '../utils/DiscordMessage'; const EMBEDS = { SAY_INFO: (data: Message | Interaction) => { - return makeInfoEmbed ({ + return makeInfoEmbed({ title: 'Say', description: `Make me say something!`, fields: [ @@ -14,73 +19,86 @@ const EMBEDS = { value: '``Your message``' } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_PERMISSION: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'You need ``VIEW_CHANNEL, SEND_MESSAGES and MANAGE_CHANNELS`` permission on this guild!', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, SUCCESSFULLY_SAID: (data: Message | Interaction) => { - return makeSuccessEmbed ({ + return makeSuccessEmbed({ title: 'Successfully said', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); } -} +}; export default class Say extends DiscordModule { - - public id = "Discord_Say"; - public commands = ["say"]; - public commandInteractionName = "say"; + public id = 'Discord_Say'; + public commands = ['say']; + public commandInteractionName = 'say'; async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { - let query; - if(data.isMessage()) { + if (data.isMessage()) { const message = data.getMessage(); - if(!message.member) return; + if (!message.member) return; - if (!message.member.permissions.has([Permissions.FLAGS.VIEW_CHANNEL, Permissions.FLAGS.SEND_MESSAGES, Permissions.FLAGS.MANAGE_CHANNELS])) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] }); + if ( + !message.member.permissions.has([ + Permissions.FLAGS.VIEW_CHANNEL, + Permissions.FLAGS.SEND_MESSAGES, + Permissions.FLAGS.MANAGE_CHANNELS + ]) + ) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] + }); - if(args.length === 0) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SAY_INFO(data.getRaw())] }); + if (args.length === 0) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.SAY_INFO(data.getRaw())] + }); - query = args.join(" "); - } - else if(data.isSlashCommand()) { + query = args.join(' '); + } else if (data.isSlashCommand()) { const interaction = data.getSlashCommand(); - if(!data.getGuild()!.members.cache.get(interaction.user.id)?.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] }); + if ( + !data + .getGuild()! + .members.cache.get(interaction.user.id) + ?.permissions.has([Permissions.FLAGS.ADMINISTRATOR]) + ) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] + }); query = interaction.options.getString('message'); } - if(data.isSlashCommand() && data.getChannel()) { + if (data.isSlashCommand() && data.getChannel()) { await data.getChannel()!.send({ content: query }); - await data.getMessageComponentInteraction().reply({ ephemeral: true, embeds: [EMBEDS.SUCCESSFULLY_SAID(data.getRaw())] }); - } - else if(data.isMessage()) { + await data + .getMessageComponentInteraction() + .reply({ ephemeral: true, embeds: [EMBEDS.SUCCESSFULLY_SAID(data.getRaw())] }); + } else if (data.isMessage()) { const message = data.getMessage(); - if(message.deletable) - await message.delete(); + if (message.deletable) await message.delete(); await data.getChannel()!.send({ content: query }); } - } -} \ No newline at end of file +} diff --git a/src/discord/Settings.ts b/src/discord/Settings.ts index db55cdb..5d12a26 100644 --- a/src/discord/Settings.ts +++ b/src/discord/Settings.ts @@ -1,10 +1,24 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; +import { + Message, + Interaction, + CommandInteraction, + Permissions, + ThreadChannel, + GuildChannel +} from 'discord.js'; -import { Message, Interaction, CommandInteraction, Permissions, ThreadChannel, GuildChannel } from "discord.js"; -import { makeInfoEmbed, makeErrorEmbed, makeSuccessEmbed, makeProcessingEmbed, sendHybridInteractionMessageResponse } from "../utils/DiscordMessage"; -import DiscordProvider from "../providers/Discord"; -import Prisma from "../providers/Prisma"; -import Cache from "../providers/Cache"; +import DiscordProvider from '../providers/Discord'; +import Prisma from '../providers/Prisma'; +import Cache from '../providers/Cache'; + +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; +import { + makeInfoEmbed, + makeErrorEmbed, + makeSuccessEmbed, + makeProcessingEmbed, + sendHybridInteractionMessageResponse +} from '../utils/DiscordMessage'; const EMBEDS = { SETTINGS_INFO: (data: Message | Interaction) => { @@ -17,312 +31,423 @@ const EMBEDS = { value: '``setPrefix`` ``setEnableServiceAnnouncement`` ``setServiceAnnouncementChannel``' } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, PROCESSING: (data: HybridInteractionMessage) => { return makeProcessingEmbed({ - icon: (data.isMessage()) ? undefined : 'โŒ›', + icon: data.isMessage() ? undefined : 'โŒ›', title: `Performing actions`, user: data.getUser() }); }, NO_PERMISSION: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'You need ``ADMINISTRATOR`` permission on this guild!', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_PREFIX_PROVIDED: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'No prefix provided', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, SERVICE_ANNOUNCEMENT_INVALID_STATUS: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'Invalid status, Use ``true`` or ``false``', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_SERVICE_ANNOUNCEMENT_STATUS_PROVIDED: async (data: Message | Interaction) => { let GuildCache = await Cache.getGuild(data.guild!.id); // TODO: Better error handling - if(typeof GuildCache === 'undefined') - throw new Error('Guild not found'); - - return makeInfoEmbed ({ + if (typeof GuildCache === 'undefined') throw new Error('Guild not found'); + + return makeInfoEmbed({ title: 'Service Announcement', - description: `Service Announcement is ${GuildCache.ServiceAnnouncement_Enabled ? "**enabled**" : "**disabled**"} on this server`, - user: (data instanceof Interaction) ? data.user : data.author + description: `Service Announcement is ${ + GuildCache.ServiceAnnouncement_Enabled ? '**enabled**' : '**disabled**' + } on this server`, + user: data instanceof Interaction ? data.user : data.author }); }, PREFIX_TOO_LONG: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'Prefix too long', description: `I bet you can't even remember that`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, PREFIX_IS_MENTION: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'Prefix cannot be mention of me', description: `You can already call me by mentioning me. I got that covered, don't worry`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, PREFIX_UPDATED: (data: Message | Interaction, newPrefix: string) => { - return makeSuccessEmbed ({ + return makeSuccessEmbed({ title: 'Prefix Updated', description: `From now onwards, I shall be called by using \`\`${newPrefix}\`\``, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, SERVICE_ANNOUNCEMENT_STATUS_UPDATED: (data: Message | Interaction, newStatus: boolean) => { - return makeSuccessEmbed ({ - title: `Service Announcement is now ${newStatus ? "enabled" : "disabled"}`, - user: (data instanceof Interaction) ? data.user : data.author + return makeSuccessEmbed({ + title: `Service Announcement is now ${newStatus ? 'enabled' : 'disabled'}`, + user: data instanceof Interaction ? data.user : data.author }); }, SERVICE_ANNOUNCEMENT_STATUS_ALREADY_SET: (data: Message | Interaction, status: boolean) => { - return makeInfoEmbed ({ - title: `Service Announcement is already ${status ? "enabled" : "disabled"}`, - user: (data instanceof Interaction) ? data.user : data.author + return makeInfoEmbed({ + title: `Service Announcement is already ${status ? 'enabled' : 'disabled'}`, + user: data instanceof Interaction ? data.user : data.author }); }, SERVICE_ANNOUNCEMENT_NO_PARAMETER: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'Missing parameter', description: `You must define service announcement channel to enable this feature`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_CHANNEL_MENTIONED: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'No channel mentioned', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_CHANNEL_FOUND: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'Cannot find that channel', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, INVALID_CHANNEL: (data: Message | Interaction, channel: GuildChannel) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'Invalid channel type, only TextChannel is supported', - description: '``' + channel.name +'``' + ' is not a text channel', - user: (data instanceof Interaction) ? data.user : data.author + description: '``' + channel.name + '``' + ' is not a text channel', + user: data instanceof Interaction ? data.user : data.author }); }, - INVALID_CHANNEL_THREAD: (data: Message | Interaction, channel: GuildChannel | ThreadChannel) => { - return makeErrorEmbed ({ + INVALID_CHANNEL_THREAD: ( + data: Message | Interaction, + channel: GuildChannel | ThreadChannel + ) => { + return makeErrorEmbed({ title: 'Thread channel is not supported', - description: '``' + channel.name +'``' + ' is a thread channel. Please use a regular text channel', - user: (data instanceof Interaction) ? data.user : data.author + description: + '``' + + channel.name + + '``' + + ' is a thread channel. Please use a regular text channel', + user: data instanceof Interaction ? data.user : data.author }); }, BOT_NO_PERMISSION: (data: Message | Interaction, channel: GuildChannel) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: `I don't have permission`, - description: 'I cannot access/send message in ' + '``' + channel.name +'``', - user: (data instanceof Interaction) ? data.user : data.author + description: 'I cannot access/send message in ' + '``' + channel.name + '``', + user: data instanceof Interaction ? data.user : data.author }); }, - SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL: (data: Message | Interaction, channel: GuildChannel) => { - return makeSuccessEmbed ({ + SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL: ( + data: Message | Interaction, + channel: GuildChannel + ) => { + return makeSuccessEmbed({ title: 'Configured Service Announcement Channel', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); - }, -} + } +}; export default class Settings extends DiscordModule { - - public id = "Discord_Settings"; - public commands = ["settings"]; - public commandInteractionName = "settings"; + public id = 'Discord_Settings'; + public commands = ['settings']; + public commandInteractionName = 'settings'; async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { - - const Guild = await Prisma.client.guild.findFirst({ where: { id: data.getGuild()!.id }}) - if(!Guild) return; + const Guild = await Prisma.client.guild.findFirst({ where: { id: data.getGuild()!.id } }); + if (!Guild) return; const funct = { - setPrefix: async(data: HybridInteractionMessage) => { - + setPrefix: async (data: HybridInteractionMessage) => { let member = data.getMember(); - if(!member) return; + if (!member) return; if (!member.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] + }); let newPrefix: string | null | undefined; - if(data.isMessage()) { + if (data.isMessage()) { let _name: string; - if(typeof args[1] === 'undefined') - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PREFIX_PROVIDED(data.getRaw())] }); + if (typeof args[1] === 'undefined') + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_PREFIX_PROVIDED(data.getRaw())] + }); let __name = args; __name.shift(); - _name = __name.join(" "); + _name = __name.join(' '); newPrefix = _name; - } - else if(data.isSlashCommand()) + } else if (data.isSlashCommand()) newPrefix = data.getSlashCommand().options.getString('prefix'); - if(!newPrefix) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PREFIX_PROVIDED(data.getRaw())] }); + if (!newPrefix) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_PREFIX_PROVIDED(data.getRaw())] + }); - if(newPrefix.length > 200) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PREFIX_TOO_LONG(data.getRaw())] }); + if (newPrefix.length > 200) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.PREFIX_TOO_LONG(data.getRaw())] + }); - if(newPrefix.startsWith(`<@!${DiscordProvider.client.user?.id}>`)) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PREFIX_IS_MENTION(data.getRaw())] }); + if (newPrefix.startsWith(`<@!${DiscordProvider.client.user?.id}>`)) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.PREFIX_IS_MENTION(data.getRaw())] + }); - let placeholder: (HybridInteractionMessage | undefined); + let placeholder: HybridInteractionMessage | undefined; - let _placeholder = await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PROCESSING(data)] }); - if (_placeholder) - placeholder = new HybridInteractionMessage(_placeholder); + let _placeholder = await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.PROCESSING(data)] + }); + if (_placeholder) placeholder = new HybridInteractionMessage(_placeholder); - await Prisma.client.guild.update({ where: { id: data.getGuild()!.id }, data: { prefix: newPrefix }}); + await Prisma.client.guild.update({ + where: { id: data.getGuild()!.id }, + data: { prefix: newPrefix } + }); Cache.updateGuildCache(data.getGuild()!.id); - if(data && data.isMessage() && placeholder && placeholder.isMessage()) - return placeholder.getMessage().edit({ embeds: [EMBEDS.PREFIX_UPDATED(data.getRaw(), newPrefix)] }); - else if(data.isSlashCommand()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PREFIX_UPDATED(data.getRaw(), newPrefix)]}, true); + if (data && data.isMessage() && placeholder && placeholder.isMessage()) + return placeholder + .getMessage() + .edit({ embeds: [EMBEDS.PREFIX_UPDATED(data.getRaw(), newPrefix)] }); + else if (data.isSlashCommand()) + return await sendHybridInteractionMessageResponse( + data, + { embeds: [EMBEDS.PREFIX_UPDATED(data.getRaw(), newPrefix)] }, + true + ); }, - setEnableServiceAnnouncement: async(data: HybridInteractionMessage) => { - + setEnableServiceAnnouncement: async (data: HybridInteractionMessage) => { let member = data.getMember(); - if(!member) return; + if (!member) return; if (!member.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] + }); let newStatus: string | null | undefined; - if(data.isMessage()) { + if (data.isMessage()) { let _name: string; - if(typeof args[1] === 'undefined') - return await sendHybridInteractionMessageResponse(data, { embeds: [await EMBEDS.NO_SERVICE_ANNOUNCEMENT_STATUS_PROVIDED(data.getRaw())] }); + if (typeof args[1] === 'undefined') + return await sendHybridInteractionMessageResponse(data, { + embeds: [ + await EMBEDS.NO_SERVICE_ANNOUNCEMENT_STATUS_PROVIDED(data.getRaw()) + ] + }); let __name = args; __name.shift(); - _name = __name.join(" "); + _name = __name.join(' '); newStatus = _name; - } - else if(data.isSlashCommand()) + } else if (data.isSlashCommand()) newStatus = data.getSlashCommand().options.getString('status')!; - if(!newStatus) - return await sendHybridInteractionMessageResponse(data, { embeds: [await EMBEDS.NO_SERVICE_ANNOUNCEMENT_STATUS_PROVIDED(data.getRaw())] }); + if (!newStatus) + return await sendHybridInteractionMessageResponse(data, { + embeds: [ + await EMBEDS.NO_SERVICE_ANNOUNCEMENT_STATUS_PROVIDED(data.getRaw()) + ] + }); - if(!["true", "false", "yes", "no", "y", "n", "enable", "disable"].includes(newStatus.toLowerCase())) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_INVALID_STATUS(data.getRaw())] }); + if ( + !['true', 'false', 'yes', 'no', 'y', 'n', 'enable', 'disable'].includes( + newStatus.toLowerCase() + ) + ) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_INVALID_STATUS(data.getRaw())] + }); await Cache.updateGuildCache(data.getGuild()!.id); let GuildCache = await Cache.getGuild(data.getGuild()!.id); - const newStatusBool = ["true", "yes", "y", "enable"].includes(newStatus.toLowerCase()) ? true : false; + const newStatusBool = ['true', 'yes', 'y', 'enable'].includes( + newStatus.toLowerCase() + ) + ? true + : false; - if(GuildCache?.ServiceAnnouncement_Enabled === newStatusBool) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_ALREADY_SET(data.getRaw(), newStatusBool)] }); + if (GuildCache?.ServiceAnnouncement_Enabled === newStatusBool) + return await sendHybridInteractionMessageResponse(data, { + embeds: [ + EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_ALREADY_SET( + data.getRaw(), + newStatusBool + ) + ] + }); - if(GuildCache?.ServiceAnnouncement_Channel === null) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_NO_PARAMETER(data.getRaw())] }); + if (GuildCache?.ServiceAnnouncement_Channel === null) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_NO_PARAMETER(data.getRaw())] + }); - let placeholder = await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PROCESSING(data)] }); + let placeholder = await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.PROCESSING(data)] + }); - await Prisma.client.guild.update( - { where: { id: data.getGuild()!.id }, - data: { + await Prisma.client.guild.update({ + where: { id: data.getGuild()!.id }, + data: { ServiceAnnouncement_Enabled: newStatusBool } }); Cache.updateGuildCache(data.getGuild()!.id); - if(data.isMessage()) - return await (placeholder as Message).edit({ embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_UPDATED(data.getRaw(), newStatusBool)]}); - else if(data.isSlashCommand()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_UPDATED(data.getRaw(), newStatusBool)]}, true); + if (data.isMessage()) + return await (placeholder as Message).edit({ + embeds: [ + EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_UPDATED(data.getRaw(), newStatusBool) + ] + }); + else if (data.isSlashCommand()) + return await sendHybridInteractionMessageResponse( + data, + { + embeds: [ + EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_UPDATED( + data.getRaw(), + newStatusBool + ) + ] + }, + true + ); }, - setServiceAnnouncementChannel: async(data: HybridInteractionMessage) => { - + setServiceAnnouncementChannel: async (data: HybridInteractionMessage) => { let member = data.getMember(); - if(!member) return; + if (!member) return; if (!member.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] }); - + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] + }); + let channel; - if(data.isMessage()) { - if(typeof args[1] === 'undefined') - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_CHANNEL_MENTIONED(data.getRaw())] }); + if (data.isMessage()) { + if (typeof args[1] === 'undefined') + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_CHANNEL_MENTIONED(data.getRaw())] + }); channel = data.getMessage().mentions.channels.first(); - } - else if(data.isSlashCommand()) + } else if (data.isSlashCommand()) channel = data.getSlashCommand().options.getChannel('channel'); - if(!channel) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_CHANNEL_FOUND(data.getRaw())] }); - + if (!channel) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_CHANNEL_FOUND(data.getRaw())] + }); + let TargetChannel = data.getGuild()!.channels.cache.get(channel.id); - if(typeof TargetChannel === 'undefined') return; + if (typeof TargetChannel === 'undefined') return; - if(TargetChannel instanceof ThreadChannel || TargetChannel.isThread()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_CHANNEL_THREAD(data.getRaw(), TargetChannel)] }); + if (TargetChannel instanceof ThreadChannel || TargetChannel.isThread()) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INVALID_CHANNEL_THREAD(data.getRaw(), TargetChannel)] + }); - if(!TargetChannel.isText()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_CHANNEL(data.getRaw(), TargetChannel)] }); + if (!TargetChannel.isText()) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INVALID_CHANNEL(data.getRaw(), TargetChannel)] + }); - if(!(data.getGuild()!.me?.permissionsIn(TargetChannel).has([Permissions.FLAGS.SEND_MESSAGES, Permissions.FLAGS.VIEW_CHANNEL]))) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.BOT_NO_PERMISSION(data.getRaw(), TargetChannel)] }); + if ( + !data + .getGuild()! + .me?.permissionsIn(TargetChannel) + .has([Permissions.FLAGS.SEND_MESSAGES, Permissions.FLAGS.VIEW_CHANNEL]) + ) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.BOT_NO_PERMISSION(data.getRaw(), TargetChannel)] + }); - let placeholder = await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PROCESSING(data)] }); + let placeholder = await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.PROCESSING(data)] + }); - await Prisma.client.guild.update({ where: {id: data.getGuild()!.id }, data: { ServiceAnnouncement_Channel: channel.id }}); + await Prisma.client.guild.update({ + where: { id: data.getGuild()!.id }, + data: { ServiceAnnouncement_Channel: channel.id } + }); - if(data.isMessage()) - return await (placeholder as Message).edit({ embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL(data.getRaw(), TargetChannel)]}); - else if(data.isSlashCommand()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL(data.getRaw(), TargetChannel)]}, true); + if (data.isMessage()) + return await (placeholder as Message).edit({ + embeds: [ + EMBEDS.SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL( + data.getRaw(), + TargetChannel + ) + ] + }); + else if (data.isSlashCommand()) + return await sendHybridInteractionMessageResponse( + data, + { + embeds: [ + EMBEDS.SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL( + data.getRaw(), + TargetChannel + ) + ] + }, + true + ); } - } + }; let query; - if(data.isMessage()) { - if(args.length === 0) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SETTINGS_INFO(data.getRaw())] }); - + if (data.isMessage()) { + if (args.length === 0) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.SETTINGS_INFO(data.getRaw())] + }); + query = args[0].toLowerCase(); - } - else if(data.isSlashCommand()) { + } else if (data.isSlashCommand()) { query = args.getSubcommand(); } - switch(query) { - case "info": - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SETTINGS_INFO(data.getRaw())] }); - case "setprefix": + switch (query) { + case 'info': + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.SETTINGS_INFO(data.getRaw())] + }); + case 'setprefix': return await funct.setPrefix(data); - case "setenableserviceannouncement": + case 'setenableserviceannouncement': return await funct.setEnableServiceAnnouncement(data); - case "setserviceannouncementchannel": + case 'setserviceannouncementchannel': return await funct.setServiceAnnouncementChannel(data); } - } -} \ No newline at end of file +} diff --git a/src/discord/Stats.ts b/src/discord/Stats.ts index 153f702..f742efb 100644 --- a/src/discord/Stats.ts +++ b/src/discord/Stats.ts @@ -1,14 +1,13 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; +import { Message, CommandInteraction, Interaction } from 'discord.js'; +import os from 'os-utils'; -import { Message, CommandInteraction, Interaction } from "discord.js"; -import { sendHybridInteractionMessageResponse, makeInfoEmbed } from "../utils/DiscordMessage"; -import DiscordProvider from "../providers/Discord"; -import os from "os-utils"; +import DiscordProvider from '../providers/Discord'; + +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; +import { sendHybridInteractionMessageResponse, makeInfoEmbed } from '../utils/DiscordMessage'; const EMBEDS = { STATS_INFO: (data: Message | Interaction) => { - let message; - return makeInfoEmbed({ title: `Stats`, icon: '๐Ÿ“Š', @@ -16,35 +15,44 @@ const EMBEDS = { fields: [ { name: '๐ŸŒโ€‚Users', - value: `${DiscordProvider.client.guilds.cache.size} servers\n${DiscordProvider.client.guilds.cache.map((g) => g.memberCount).reduce((a, c) => a + c)} users`, + value: `${ + DiscordProvider.client.guilds.cache.size + } servers\n${DiscordProvider.client.guilds.cache + .map((g) => g.memberCount) + .reduce((a, c) => a + c)} users`, inline: true }, { name: '๐ŸŸขโ€‚Uptime since', - value: `System: \nProcess: `, + value: `System: \nProcess: `, inline: true } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); } -} +}; export default class Stats extends DiscordModule { - - public id = "Discord_Stats"; - public commands = ["stats"]; - public commandInteractionName = "stats"; - + public id = 'Discord_Stats'; + public commands = ['stats']; + public commandInteractionName = 'stats'; + async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { - return await sendHybridInteractionMessageResponse(data, { embeds:[EMBEDS.STATS_INFO(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.STATS_INFO(data.getRaw())] + }); } -} \ No newline at end of file +} diff --git a/src/discord/UserInfo.ts b/src/discord/UserInfo.ts index baf9eea..807e7be 100644 --- a/src/discord/UserInfo.ts +++ b/src/discord/UserInfo.ts @@ -1,12 +1,16 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; +import { Message, Interaction, CommandInteraction } from 'discord.js'; +import { getColorFromURL } from 'color-thief-node'; -import { Message, Interaction, CommandInteraction } from "discord.js"; -import { sendHybridInteractionMessageResponse, makeErrorEmbed, makeInfoEmbed } from "../utils/DiscordMessage"; -import { getColorFromURL } from "color-thief-node"; +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; +import { + sendHybridInteractionMessageResponse, + makeErrorEmbed, + makeInfoEmbed +} from '../utils/DiscordMessage'; const EMBEDS = { SAY_INFO: (data: Message | Interaction) => { - return makeInfoEmbed ({ + return makeInfoEmbed({ title: 'User Info', description: `View info on discord user`, fields: [ @@ -15,75 +19,75 @@ const EMBEDS = { value: '``Discord user mention or id``' } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, USER_NOT_FOUND: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: 'That user cannot be found!', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); } -} +}; export default class UserInfo extends DiscordModule { - - public id = "Discord_UserInfo"; - public commands = ["userinfo"]; - public commandInteractionName = "userinfo"; + public id = 'Discord_UserInfo'; + public commands = ['userinfo']; + public commandInteractionName = 'userinfo'; async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { let query; - if(data.isMessage()) { - if(args.length === 0) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SAY_INFO(data.getRaw())] }); + if (data.isMessage()) { + if (args.length === 0) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.SAY_INFO(data.getRaw())] + }); - if(typeof data.getMessage().mentions.users.first() !== 'undefined') + if (typeof data.getMessage().mentions.users.first() !== 'undefined') query = data.getMessage().mentions.users.first()?.id; - else - query = args[0]; - } - else if(data.isSlashCommand()) + else query = args[0]; + } else if (data.isSlashCommand()) query = data.getSlashCommand().options.getUser('user')?.id; // Find the user want to look up let TargetMember = (await data.getGuild()!.members.fetch()).get(query); - if(!TargetMember) return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.USER_NOT_FOUND(data.getRaw())] }); + if (!TargetMember) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.USER_NOT_FOUND(data.getRaw())] + }); - - if(data.isSlashCommand()) - await data.getMessageComponentInteraction().deferReply(); + if (data.isSlashCommand()) await data.getMessageComponentInteraction().deferReply(); let readableStatus: string; - - switch(TargetMember.presence?.status) { - case "online": - readableStatus = "๐ŸŸข Online"; + + switch (TargetMember.presence?.status) { + case 'online': + readableStatus = '๐ŸŸข Online'; break; - case "idle": - readableStatus = "๐ŸŒ™ Idle"; + case 'idle': + readableStatus = '๐ŸŒ™ Idle'; break; - case "dnd": - readableStatus = "โ›” Do not disturb"; + case 'dnd': + readableStatus = 'โ›” Do not disturb'; break; - case "offline": - readableStatus = "โšซ Offline"; + case 'offline': + readableStatus = 'โšซ Offline'; break; default: - readableStatus = "โ“ Unknown"; + readableStatus = 'โ“ Unknown'; break; } - const embed = makeInfoEmbed ({ + const embed = makeInfoEmbed({ icon: '', title: `${TargetMember.user.tag}`, fields: [ @@ -95,49 +99,73 @@ export default class UserInfo extends DiscordModule { user: data.getUser() }); - if(TargetMember.presence?.activities) - for(let activity of TargetMember.presence?.activities) { - if(activity.type === "CUSTOM") - embed.addField( `โœจ ${activity.name}`, `${!activity.emoji ? '' : `${activity.emoji?.identifier.startsWith('%') ? activity.emoji?.name : '<' + activity.emoji?.identifier + '>'}`} ${activity.state === null ? '' : activity.state} - \u200b`, true); + if (TargetMember.presence?.activities) + for (let activity of TargetMember.presence?.activities) { + if (activity.type === 'CUSTOM') + embed.addField( + `โœจ ${activity.name}`, + `${ + !activity.emoji + ? '' + : `${ + activity.emoji?.identifier.startsWith('%') + ? activity.emoji?.name + : '<' + activity.emoji?.identifier + '>' + }` + } ${activity.state === null ? '' : activity.state} + \u200b`, + true + ); else { - let emoji = ""; - switch(activity.type) { - case "PLAYING": - emoji = "๐Ÿ•น "; + let emoji = ''; + switch (activity.type) { + case 'PLAYING': + emoji = '๐Ÿ•น '; break; - case "STREAMING": - emoji = "๐Ÿ”ด "; + case 'STREAMING': + emoji = '๐Ÿ”ด '; break; - case "LISTENING": - emoji = "๐ŸŽต "; + case 'LISTENING': + emoji = '๐ŸŽต '; break; - case "WATCHING": - emoji = "๐Ÿ“บ "; + case 'WATCHING': + emoji = '๐Ÿ“บ '; break; - case "COMPETING": - emoji = "๐ŸŒ  "; + case 'COMPETING': + emoji = '๐ŸŒ  '; break; } - embed.addField( `${emoji}${activity.type.toLowerCase().charAt(0).toUpperCase() + activity.type.toLowerCase().slice(1)} ${activity.name}`, - `${activity.details === null ? '' : activity.details} + embed.addField( + `${emoji}${ + activity.type.toLowerCase().charAt(0).toUpperCase() + + activity.type.toLowerCase().slice(1) + } ${activity.name}`, + `${activity.details === null ? '' : activity.details} ${activity.state === null ? '' : activity.state} Since - \u200b`, true); + \u200b`, + true + ); } } - embed.addField(`๐Ÿ“ฐ Information on this guild`, `${ - (TargetMember.joinedAt === null) ? 'Cannot determine joined date' : `Joined `} - ${(TargetMember.id === data.getGuild()!.ownerId) ? 'Owner of this guild ๐Ÿ‘‘' : ''} - `); - - try { - const colorthief = await getColorFromURL(TargetMember.user.displayAvatarURL().replace('.webp', '.jpg')); - embed.setColor(colorthief); - } catch (err) { + embed.addField( + `๐Ÿ“ฐ Information on this guild`, + `${ + TargetMember.joinedAt === null + ? 'Cannot determine joined date' + : `Joined ` + } + ${TargetMember.id === data.getGuild()!.ownerId ? 'Owner of this guild ๐Ÿ‘‘' : ''} + ` + ); - } + try { + const colorthief = await getColorFromURL( + TargetMember.user.displayAvatarURL().replace('.webp', '.jpg') + ); + embed.setColor(colorthief); + } catch (err) {} embed.setThumbnail(TargetMember.user.displayAvatarURL()); embed.setAuthor({ @@ -146,6 +174,5 @@ export default class UserInfo extends DiscordModule { }); return await sendHybridInteractionMessageResponse(data, { embeds: [embed] }); - } -} \ No newline at end of file +} diff --git a/src/discord/developer/Debug.ts b/src/discord/developer/Debug.ts index 5c34184..cedf472 100644 --- a/src/discord/developer/Debug.ts +++ b/src/discord/developer/Debug.ts @@ -1,10 +1,21 @@ -import DiscordModule, { HybridInteractionMessage } from "../../utils/DiscordModule"; +import { + Message, + Interaction, + CommandInteraction, + MessageActionRow, + MessageButton, + ButtonInteraction +} from 'discord.js'; -import { Message, Interaction, CommandInteraction, MessageActionRow, MessageButton, ButtonInteraction } from "discord.js"; -import { makeInfoEmbed, makeErrorEmbed, sendHybridInteractionMessageResponse, sendMessageOrInteractionResponse } from "../../utils/DiscordMessage"; -import DiscordProvider from "../../providers/Discord"; -import DiscordMusicPlayer from "../../providers/DiscordMusicPlayer"; -import Users from "../../services/Users"; +import DiscordModule, { HybridInteractionMessage } from '../../utils/DiscordModule'; +import { + makeInfoEmbed, + makeErrorEmbed, + sendHybridInteractionMessageResponse +} from '../../utils/DiscordMessage'; + +import DiscordMusicPlayer from '../../providers/DiscordMusicPlayer'; +import Users from '../../services/Users'; const EMBEDS = { DEBUG_INFO: (data: Message | Interaction) => { @@ -17,14 +28,14 @@ const EMBEDS = { value: '``invalidInteraction`` ``crashMusicPlayer`` ``crash`` ``activemusicplayer``' } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, INVALID_TEST: (data: Message | Interaction) => { return makeInfoEmbed({ title: 'Click button below to test invalid interaction', description: `The interaction will be failed`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, CRASHING: (data: Message | Interaction) => { @@ -32,31 +43,30 @@ const EMBEDS = { icon: '๐Ÿ’€', title: 'Crashing myself', description: `Sayonara.... cruel world`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, ACTIVE_MUSIC_PLAYERS: (data: Message | Interaction, totalplayers: Map) => { return makeInfoEmbed({ icon: '๐ŸŽต', title: `Total active music players: ${totalplayers.size}`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NOT_DEVELOPER: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'Developer only', description: `This command is restricted to the developers only`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); - }, -} + } +}; export default class Debug extends DiscordModule { + public id = 'Discord_Developer_Debug'; + public commands = ['debug', 'dbg']; + public commandInteractionName = 'debug'; - public id = "Discord_Developer_Debug"; - public commands = ["debug", "dbg"]; - public commandInteractionName = "debug"; - async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } @@ -66,84 +76,100 @@ export default class Debug extends DiscordModule { } async GuildButtonInteractionCreate(data: ButtonInteraction) { - if(data.customId !== "dev_make_invalid_interaction") return; + if (data.customId !== 'dev_make_invalid_interaction') return; const hybridData = new HybridInteractionMessage(data); const user = hybridData.getUser(); - if(!user) return; + if (!user) return; if (!Users.isDeveloper(user.id)) - return await sendHybridInteractionMessageResponse(hybridData, { embeds: [EMBEDS.NOT_DEVELOPER(hybridData.getRaw())] }); + return await sendHybridInteractionMessageResponse(hybridData, { + embeds: [EMBEDS.NOT_DEVELOPER(hybridData.getRaw())] + }); setTimeout(async () => { - await sendHybridInteractionMessageResponse(hybridData, { content: 'dev_make_invalid_interaction' }); - }, 7 * 1000) + await sendHybridInteractionMessageResponse(hybridData, { + content: 'dev_make_invalid_interaction' + }); + }, 7 * 1000); } async run(data: HybridInteractionMessage, args: any) { - const guild = data.getGuild(); const user = data.getUser(); const channel = data.getChannel(); - - if(!guild || !user || !channel) return; + + if (!guild || !user || !channel) return; if (!Users.isDeveloper(user.id)) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NOT_DEVELOPER(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NOT_DEVELOPER(data.getRaw())] + }); const funct = { crash: async (data: HybridInteractionMessage) => { - await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.CRASHING(data.getRaw())] }); - throw new Error("Manually crashed by debug command"); + await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.CRASHING(data.getRaw())] + }); + throw new Error('Manually crashed by debug command'); }, crashMusicPlayer: async (data: HybridInteractionMessage) => { const instance = DiscordMusicPlayer.getGuildInstance(guild.id); - if(!instance) return; + if (!instance) return; instance._fake_error_on_player(); }, activeMusicPlayer: async (data: HybridInteractionMessage) => { - await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ACTIVE_MUSIC_PLAYERS(data.getRaw(), DiscordMusicPlayer.GuildQueue)] }); + await sendHybridInteractionMessageResponse(data, { + embeds: [ + EMBEDS.ACTIVE_MUSIC_PLAYERS(data.getRaw(), DiscordMusicPlayer.GuildQueue) + ] + }); }, invalidInteraction: async (data: HybridInteractionMessage) => { - - const row = new MessageActionRow() - .addComponents( - new MessageButton() - .setEmoji('๐Ÿ˜ฅ') - .setLabel('โ€‚Make invalid interaction (Wait 7 seconds, check error in console or logs)') - .setCustomId('dev_make_invalid_interaction') - .setStyle('PRIMARY'), - ) - await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_TEST(data.getRaw())], components: [row] }); + const row = new MessageActionRow().addComponents( + new MessageButton() + .setEmoji('๐Ÿ˜ฅ') + .setLabel( + 'โ€‚Make invalid interaction (Wait 7 seconds, check error in console or logs)' + ) + .setCustomId('dev_make_invalid_interaction') + .setStyle('PRIMARY') + ); + await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INVALID_TEST(data.getRaw())], + components: [row] + }); } - } + }; let query; if (data.isMessage()) { if (args.length === 0) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.DEBUG_INFO(data.getRaw())] }); - + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.DEBUG_INFO(data.getRaw())] + }); + query = args[0].toLowerCase(); - } - else if (data.isSlashCommand()) { + } else if (data.isSlashCommand()) { query = args.getSubcommand(); } switch (query) { - case "info": - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.DEBUG_INFO(data.getRaw())] }); - case "crash": + case 'info': + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.DEBUG_INFO(data.getRaw())] + }); + case 'crash': return await funct.crash(data); - case "invalidinteraction": + case 'invalidinteraction': return await funct.invalidInteraction(data); - case "crashmusicplayer": + case 'crashmusicplayer': return await funct.crashMusicPlayer(data); - case "activemusicplayer": + case 'activemusicplayer': return await funct.activeMusicPlayer(data); } - } -} \ No newline at end of file +} diff --git a/src/discord/developer/ServiceAnnouncement.ts b/src/discord/developer/ServiceAnnouncement.ts index db97345..f721fae 100644 --- a/src/discord/developer/ServiceAnnouncement.ts +++ b/src/discord/developer/ServiceAnnouncement.ts @@ -1,16 +1,25 @@ -import DiscordModule, { HybridInteractionMessage } from "../../utils/DiscordModule"; +import { Message, MessageEmbed, Interaction, CommandInteraction, TextChannel } from 'discord.js'; +import { Promise } from 'bluebird'; +import fs from 'fs'; +import path from 'path'; -import { Message, MessageEmbed, Interaction, CommandInteraction, TextChannel } from "discord.js"; -import { makeInfoEmbed, makeErrorEmbed, makeSuccessEmbed, makeProcessingEmbed, makeWarningEmbed, sendHybridInteractionMessageResponse, sendMessage } from "../../utils/DiscordMessage"; -import DiscordProvider from "../../providers/Discord"; -import Prisma from "../../providers/Prisma"; -import Users from "../../services/Users"; +import { Guild } from '@prisma/client'; -import { Promise } from "bluebird"; -import fs from "fs"; -import path from "path"; -import Logger from "../../libs/Logger"; -import { Guild } from "@prisma/client"; +import DiscordModule, { HybridInteractionMessage } from '../../utils/DiscordModule'; +import { + makeInfoEmbed, + makeErrorEmbed, + makeSuccessEmbed, + makeProcessingEmbed, + makeWarningEmbed, + sendHybridInteractionMessageResponse, + sendMessage +} from '../../utils/DiscordMessage'; + +import Logger from '../../libs/Logger'; +import DiscordProvider from '../../providers/Discord'; +import Prisma from '../../providers/Prisma'; +import Users from '../../services/Users'; const EMBEDS = { ANNOUNCEMENT_INFO: (data: Message | Interaction) => { @@ -23,14 +32,14 @@ const EMBEDS = { value: '``reload`` ``previewNews`` ``sendNews`` ``previewMaintenance`` ``sendMaintenance`` ``previewMessage`` ``sendMessage`` ``previewAlert`` ``sendAlert``' } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NOT_DEVELOPER: (data: Message | Interaction) => { return makeErrorEmbed({ title: 'Developer only', description: `This command is restricted to the developers only`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, MAKE_PAYLOAD: (payload: any) => { @@ -38,10 +47,9 @@ const EMBEDS = { payload.footer = { text: `${user?.username}`, iconURL: `${user?.displayAvatarURL()}?size=4096` - } + }; - if (!payload.timestamp) - payload.timestamp = new Date(); + if (!payload.timestamp) payload.timestamp = new Date(); if (payload.thumbnail?.url === 'bot_avatar') payload.thumbnail.url = `${user?.displayAvatarURL()}?size=4096`; @@ -50,95 +58,95 @@ const EMBEDS = { payload.image.url = `${user?.displayAvatarURL()}?size=4096`; if (payload.description) - payload.description = payload.description.replaceAll('{bot_username}', user?.username) + payload.description = payload.description.replaceAll('{bot_username}', user?.username); - return new MessageEmbed(payload) + return new MessageEmbed(payload); }, RELOADED: (data: Message | Interaction) => { return makeSuccessEmbed({ title: 'Service Announcement Configuration Reloaded', - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, RELOAD_ERROR: (data: Message | Interaction, error: string) => { return makeErrorEmbed({ title: 'Unable to reload Service Announcement Configuration', description: `\`\`\`${error}\`\`\``, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, SENDING_SERVICE_ANNOUNCEMENT: (data: Message | Interaction) => { return makeProcessingEmbed({ title: 'Service Announcement', description: `Broadcasting Service Announcement`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, SERVICE_ANNOUNCEMENT_SENT: (data: Message | Interaction) => { return makeSuccessEmbed({ title: 'Service Announcement', description: `Broadcasted Service Announcement`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, SERVICE_ANNOUNCEMENT_SENT_WITH_ERRORS: (data: Message | Interaction) => { return makeWarningEmbed({ title: 'Service Announcement', description: `Broadcasted Service Announcement with errors, check console for more info`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); - }, -} + } +}; let Announcements = { News: { - color: "#FAEDF0", + color: '#FAEDF0', title: '๐Ÿ“ฐโ€‚Newsletter', description: 'Some description here', thumbnail: { - url: 'bot_avatar', + url: 'bot_avatar' } }, Maintenance: { - color: "#383b80", + color: '#383b80', title: '๐Ÿ”งโ€‚Maintenance', description: 'The bot is going offline for maintenance.', thumbnail: { - url: 'bot_avatar', + url: 'bot_avatar' } }, Message: { - color: "#A1DE93", + color: '#A1DE93', title: 'โœ‰๏ธโ€‚Message', description: 'Some description here', thumbnail: { - url: 'bot_avatar', + url: 'bot_avatar' } }, Alert: { - color: "#EC255A", + color: '#EC255A', title: '๐Ÿšจโ€‚Alert', description: 'Some description here', thumbnail: { - url: 'bot_avatar', + url: 'bot_avatar' } } - -} +}; export default class ServiceAnnouncement extends DiscordModule { - - public id = "Discord_Developer_ServiceAnnouncement"; - public commands = ["serviceannouncement"]; - public commandInteractionName = "serviceannouncement"; + public id = 'Discord_Developer_ServiceAnnouncement'; + public commands = ['serviceannouncement']; + public commandInteractionName = 'serviceannouncement'; async Init() { if (fs.existsSync(path.join(process.cwd(), 'configs/ServiceAnnouncement.json'))) { try { - const rawData = fs.readFileSync(path.join(process.cwd(), 'configs/ServiceAnnouncement.json')); + const rawData = fs.readFileSync( + path.join(process.cwd(), 'configs/ServiceAnnouncement.json') + ); const jsonData = JSON.parse(rawData.toString()); Announcements = jsonData; } catch (err) { - Logger.error("Unable to load custom ServiceAnnouncement config: " + err); + Logger.error('Unable to load custom ServiceAnnouncement config: ' + err); } } } @@ -147,47 +155,65 @@ export default class ServiceAnnouncement extends DiscordModule { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { - if (!Users.isDeveloper(data.getUser()!.id)) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NOT_DEVELOPER(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NOT_DEVELOPER(data.getRaw())] + }); const channel = data.getChannel(); - if(!channel) return; + if (!channel) return; const funct = { reload: async (data: HybridInteractionMessage) => { - if (fs.existsSync(path.join(process.cwd(), 'configs/ServiceAnnouncement.json'))) { try { - const rawData = fs.readFileSync(path.join(process.cwd(), 'configs/ServiceAnnouncement.json')); + const rawData = fs.readFileSync( + path.join(process.cwd(), 'configs/ServiceAnnouncement.json') + ); const jsonData = JSON.parse(rawData.toString()); Announcements = jsonData; } catch (err: any) { - Logger.error("Unable to load custom ServiceAnnouncement config: " + err); - return await sendMessage(channel, undefined, { embeds: [EMBEDS.RELOAD_ERROR(data.getRaw(), err)] }); + Logger.error('Unable to load custom ServiceAnnouncement config: ' + err); + return await sendMessage(channel, undefined, { + embeds: [EMBEDS.RELOAD_ERROR(data.getRaw(), err)] + }); } } else { - fs.writeFileSync(path.join(process.cwd(), 'configs/ServiceAnnouncement.json'), JSON.stringify(Announcements, null, 4), 'utf8'); + fs.writeFileSync( + path.join(process.cwd(), 'configs/ServiceAnnouncement.json'), + JSON.stringify(Announcements, null, 4), + 'utf8' + ); } - return await sendMessage(channel, undefined, { embeds: [EMBEDS.RELOADED(data.getRaw())] }); + return await sendMessage(channel, undefined, { + embeds: [EMBEDS.RELOADED(data.getRaw())] + }); }, previewNews: async (data: HybridInteractionMessage) => { - return await sendMessage(channel, undefined, { embeds: [EMBEDS.MAKE_PAYLOAD(Announcements.News)] }); + return await sendMessage(channel, undefined, { + embeds: [EMBEDS.MAKE_PAYLOAD(Announcements.News)] + }); }, previewMaintenance: async (data: HybridInteractionMessage) => { - return await sendMessage(channel, undefined, { embeds: [EMBEDS.MAKE_PAYLOAD(Announcements.Maintenance)] }); + return await sendMessage(channel, undefined, { + embeds: [EMBEDS.MAKE_PAYLOAD(Announcements.Maintenance)] + }); }, previewMessage: async (data: HybridInteractionMessage) => { - return await sendMessage(channel, undefined, { embeds: [EMBEDS.MAKE_PAYLOAD(Announcements.Message)] }); + return await sendMessage(channel, undefined, { + embeds: [EMBEDS.MAKE_PAYLOAD(Announcements.Message)] + }); }, previewAlert: async (data: HybridInteractionMessage) => { - return await sendMessage(channel, undefined, { embeds: [EMBEDS.MAKE_PAYLOAD(Announcements.Alert)] }); + return await sendMessage(channel, undefined, { + embeds: [EMBEDS.MAKE_PAYLOAD(Announcements.Alert)] + }); }, publishServiceAnnouncement: async (data: HybridInteractionMessage, embed: any) => { const Guilds = await Prisma.client.guild.findMany({}); @@ -201,11 +227,15 @@ export default class ServiceAnnouncement extends DiscordModule { let channel = undefined; try { - channel = await DiscordProvider.client.channels.fetch(Guild.ServiceAnnouncement_Channel) as TextChannel; + channel = (await DiscordProvider.client.channels.fetch( + Guild.ServiceAnnouncement_Channel + )) as TextChannel; } catch (err) { withError = true; const guildObject = DiscordProvider.client.guilds.cache.get(Guild.id); - Logger.warn(`Unable to find channel for Service Announcement to ${guildObject?.name} (${Guild.id}) (Channel ID: ${Guild.ServiceAnnouncement_Channel})`); + Logger.warn( + `Unable to find channel for Service Announcement to ${guildObject?.name} (${Guild.id}) (Channel ID: ${Guild.ServiceAnnouncement_Channel})` + ); continue; } @@ -213,83 +243,121 @@ export default class ServiceAnnouncement extends DiscordModule { toSend.set(Guild, channel); } - let placeholder: (HybridInteractionMessage | undefined); + let placeholder: HybridInteractionMessage | undefined; - let _placeholder = await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SENDING_SERVICE_ANNOUNCEMENT(data.getRaw())] }, true); - if (_placeholder) - placeholder = new HybridInteractionMessage(_placeholder); + let _placeholder = await sendHybridInteractionMessageResponse( + data, + { embeds: [EMBEDS.SENDING_SERVICE_ANNOUNCEMENT(data.getRaw())] }, + true + ); + if (_placeholder) placeholder = new HybridInteractionMessage(_placeholder); - await Promise.map(toSend, element => { - return new Promise(async (resolve, reject) => { - let Guild: Guild = element[0]; - let Channel: TextChannel = element[1]; - try { - const guildObject = DiscordProvider.client.guilds.cache.get(Guild.id); - if (!guildObject) - throw new Error('Guild not found'); - Logger.info(`Sending Service Announcement to ${guildObject?.name} (${guildObject.id}) #${Channel.name} (${Channel.id})`); - await sendMessage(Channel, undefined, { embeds: [EMBEDS.MAKE_PAYLOAD(embed)] }) - } catch (err) { - withError = true; - const guildObject = DiscordProvider.client.guilds.cache.get(Guild.id); - if (guildObject) - Logger.info(`Unable to send Service Announcement to ${guildObject?.name} (${guildObject.id}) #${Channel.name} (${Channel.id})`); + await Promise.map( + toSend, + (element) => { + return new Promise(async (resolve, reject) => { + let Guild: Guild = element[0]; + let Channel: TextChannel = element[1]; + try { + const guildObject = DiscordProvider.client.guilds.cache.get( + Guild.id + ); + if (!guildObject) throw new Error('Guild not found'); + Logger.info( + `Sending Service Announcement to ${guildObject?.name} (${guildObject.id}) #${Channel.name} (${Channel.id})` + ); + await sendMessage(Channel, undefined, { + embeds: [EMBEDS.MAKE_PAYLOAD(embed)] + }); + } catch (err) { + withError = true; + const guildObject = DiscordProvider.client.guilds.cache.get( + Guild.id + ); + if (guildObject) + Logger.info( + `Unable to send Service Announcement to ${guildObject?.name} (${guildObject.id}) #${Channel.name} (${Channel.id})` + ); - reject(err); - } + reject(err); + } - await new Promise(resolve => setTimeout(resolve, 1000)); - resolve(); - }); - }, { concurrency: 2 }); + await new Promise((resolve) => setTimeout(resolve, 1000)); + resolve(); + }); + }, + { concurrency: 2 } + ); if (withError) { - if(data && data.isMessage() && placeholder && placeholder.isMessage()) - return placeholder.getMessage().edit({ embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT_WITH_ERRORS(data.getRaw())] }); - else if(data.isSlashCommand()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT_WITH_ERRORS(data.getRaw())] }, true); - } - else { - if(data && data.isMessage() && placeholder && placeholder.isMessage()) - return placeholder.getMessage().edit({ embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT(data.getRaw())] }); - else if(data.isSlashCommand()) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT(data.getRaw())] }, true); + if (data && data.isMessage() && placeholder && placeholder.isMessage()) + return placeholder + .getMessage() + .edit({ + embeds: [ + EMBEDS.SERVICE_ANNOUNCEMENT_SENT_WITH_ERRORS(data.getRaw()) + ] + }); + else if (data.isSlashCommand()) + return await sendHybridInteractionMessageResponse( + data, + { + embeds: [ + EMBEDS.SERVICE_ANNOUNCEMENT_SENT_WITH_ERRORS(data.getRaw()) + ] + }, + true + ); + } else { + if (data && data.isMessage() && placeholder && placeholder.isMessage()) + return placeholder + .getMessage() + .edit({ embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT(data.getRaw())] }); + else if (data.isSlashCommand()) + return await sendHybridInteractionMessageResponse( + data, + { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT(data.getRaw())] }, + true + ); } } - } + }; let query; if (data.isMessage()) { if (args.length === 0) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ANNOUNCEMENT_INFO(data.getRaw())] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.ANNOUNCEMENT_INFO(data.getRaw())] + }); query = args[0].toLowerCase(); - } - else if (data.isSlashCommand()) { + } else if (data.isSlashCommand()) { query = args.getSubcommand(); } switch (query) { - case "info": - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ANNOUNCEMENT_INFO(data.getRaw())] }); - case "reload": + case 'info': + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.ANNOUNCEMENT_INFO(data.getRaw())] + }); + case 'reload': return await funct.reload(data); - case "previewnews": + case 'previewnews': return await funct.previewNews(data); - case "previewmaintenance": + case 'previewmaintenance': return await funct.previewMaintenance(data); - case "previewmessage": + case 'previewmessage': return await funct.previewMessage(data); - case "previewalert": + case 'previewalert': return await funct.previewAlert(data); - case "sendnews": + case 'sendnews': return await funct.publishServiceAnnouncement(data, Announcements.News); - case "sendmaintenance": + case 'sendmaintenance': return await funct.publishServiceAnnouncement(data, Announcements.Maintenance); - case "sendmessage": + case 'sendmessage': return await funct.publishServiceAnnouncement(data, Announcements.Message); - case "sendalert": + case 'sendalert': return await funct.publishServiceAnnouncement(data, Announcements.Alert); } } -} \ No newline at end of file +} diff --git a/src/discord/osu.ts b/src/discord/osu.ts index e64f294..4375a3c 100644 --- a/src/discord/osu.ts +++ b/src/discord/osu.ts @@ -1,16 +1,27 @@ -import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; - -import { Message, MessageActionRow, MessageButton, Interaction, CommandInteraction } from "discord.js"; -import { makeInfoEmbed, makeErrorEmbed, sendHybridInteractionMessageResponse } from "../utils/DiscordMessage"; -import Prisma from "../providers/Prisma"; -import osuAPI from "../providers/osuAPI"; -import { countryCodeEmoji } from "country-code-emoji"; -import countryLookup from "country-code-lookup"; +import { + Message, + MessageActionRow, + MessageButton, + Interaction, + CommandInteraction +} from 'discord.js'; import validator from 'validator'; +import countryLookup from 'country-code-lookup'; +import { countryCodeEmoji } from 'country-code-emoji'; + +import Prisma from '../providers/Prisma'; +import osuAPI from '../providers/osuAPI'; + +import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule'; +import { + makeInfoEmbed, + makeErrorEmbed, + sendHybridInteractionMessageResponse +} from '../utils/DiscordMessage'; const EMBEDS = { - osu_INFO:(data: Message | Interaction) => { - return makeInfoEmbed ({ + osu_INFO: (data: Message | Interaction) => { + return makeInfoEmbed({ title: 'osu!', description: `[osu!](https://osu.ppy.sh/home) is a free-to-play rhythm game primarily developed, published, and created by Dean "peppy" Herbert`, fields: [ @@ -23,172 +34,211 @@ const EMBEDS = { value: '``user``' } ], - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_USER_FOUND: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: `That user doesn't exists on osu!`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_USER_MENTIONED: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: `No osu! username or user id provided`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, INVALID_USER_MENTIONED: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: `Not a valid osu username or id`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, INVALID_BEATMAP_ID_MENTIONED: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: `Not a valid osu beatmap id`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_BEATMAP_FOUND: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: `That beatmap doesn't exists on osu!`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NO_BEATMAP_MENTIONED: (data: Message | Interaction) => { - return makeErrorEmbed ({ + return makeErrorEmbed({ title: `No osu! beatmap id provided`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); } -} +}; export default class osu extends DiscordModule { - - public id = "Discord_osu"; - public commands = ["osu"]; - public commandInteractionName = "osu"; + public id = 'Discord_osu'; + public commands = ['osu']; + public commandInteractionName = 'osu'; async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { - - const Guild = await Prisma.client.guild.findFirst({ where: { id: data.getGuild()!.id }}) - if(!Guild) return; - + const Guild = await Prisma.client.guild.findFirst({ where: { id: data.getGuild()!.id } }); + if (!Guild) return; + const funct = { - user: async(data: HybridInteractionMessage) => { - + user: async (data: HybridInteractionMessage) => { let user; - if(data.isMessage()) { - if(typeof args[1] === 'undefined') - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_USER_MENTIONED(data.getRaw())] }); + if (data.isMessage()) { + if (typeof args[1] === 'undefined') + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_USER_MENTIONED(data.getRaw())] + }); const [removed, ...newArgs] = args; - user = newArgs.join(" "); - } - else if(data.isSlashCommand()) + user = newArgs.join(' '); + } else if (data.isSlashCommand()) user = data.getSlashCommand().options.getString('user'); - - if(!validator.isNumeric(user) && !this.validate_osu_username(user)) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_USER_MENTIONED(data.getRaw())] }); + if (!validator.isNumeric(user) && !this.validate_osu_username(user)) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INVALID_USER_MENTIONED(data.getRaw())] + }); let result = await osuAPI.client.getUser({ u: user }); - if(result instanceof Array && result.length === 0) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_USER_FOUND(data.getRaw())] }); + if (result instanceof Array && result.length === 0) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_USER_FOUND(data.getRaw())] + }); - if(data.isSlashCommand()) { + if (data.isSlashCommand()) { await data.getSlashCommand().deferReply(); } const level = { - number: (Math.round((result.level + Number.EPSILON) * 100) / 100).toFixed(2).split('.')[0], - progression: (Math.round((result.level + Number.EPSILON) * 100) / 100).toFixed(2).split('.')[1] - } - const embed = makeInfoEmbed ({ + number: (Math.round((result.level + Number.EPSILON) * 100) / 100) + .toFixed(2) + .split('.')[0], + progression: (Math.round((result.level + Number.EPSILON) * 100) / 100) + .toFixed(2) + .split('.')[1] + }; + const embed = makeInfoEmbed({ icon: '', title: `${countryCodeEmoji(result.country)} ${result.name}`, //description: `${member.user.username}#${member.user.discriminator} (${member.user.id})`, fields: [ { name: `๐Ÿ† Level **${level.number}** (${level.progression}% progress to the next level)`, - value: `Play Count **${this.numberWithCommas(result.counts.plays)}**, totaling in **${this.numberWithCommas(parseFloat(((Math.round(((result.secondsPlayed / (60 * 60)) + Number.EPSILON) * 100) / 100).toFixed(2))))} ${result.secondsPlayed < 60 ? 'hour' : 'hours'}** of songs played - \u200b`, + value: `Play Count **${this.numberWithCommas( + result.counts.plays + )}**, totaling in **${this.numberWithCommas( + parseFloat( + ( + Math.round( + (result.secondsPlayed / (60 * 60) + Number.EPSILON) * + 100 + ) / 100 + ).toFixed(2) + ) + )} ${result.secondsPlayed < 60 ? 'hour' : 'hours'}** of songs played + \u200b` }, { - name: "๐ŸŒŽ World Ranking", + name: '๐ŸŒŽ World Ranking', value: `**#${this.numberWithCommas(result.pp.rank)}**`, inline: true }, { name: `${countryCodeEmoji(result.country)} Country Ranking`, - value: `**#${this.numberWithCommas(result.pp.countryRank)}** ${countryLookup.byInternet(result.country)!.country}`, + value: `**#${this.numberWithCommas(result.pp.countryRank)}** ${ + countryLookup.byInternet(result.country)!.country + }`, inline: true }, { - name: "๐ŸŽ€ Total Score", + name: '๐ŸŽ€ Total Score', value: `**${this.numberWithCommas(result.scores.total)}**`, inline: true }, { - name: "โœจ PP", + name: 'โœจ PP', value: `**${this.numberWithCommas(result.pp.raw)}pp**`, inline: true }, { - name: "โญ• Hit Accuracy", + name: 'โญ• Hit Accuracy', value: `**${result.accuracyFormatted}**`, inline: true }, { - name: "๐ŸŒ  Ranked Score", + name: '๐ŸŒ  Ranked Score', value: `**${this.numberWithCommas(result.scores.ranked)}** \u200b`, inline: true }, { - name: "๐Ÿฅ‡ SSH", + name: '๐Ÿฅ‡ SSH', value: `**${this.numberWithCommas(result.counts.SSH)}**`, inline: true }, { - name: "๐Ÿฅ‡ SH", + name: '๐Ÿฅ‡ SH', value: `**${this.numberWithCommas(result.counts.SH)}**`, inline: true }, { - name: "๐Ÿฅ‡ SS", + name: '๐Ÿฅ‡ SS', value: `**${this.numberWithCommas(result.counts.SS)}**`, inline: true }, { - name: "๐Ÿฅˆ S", + name: '๐Ÿฅˆ S', value: `**${this.numberWithCommas(result.counts.S)}**`, inline: true }, { - name: "๐Ÿฅ‰ A", + name: '๐Ÿฅ‰ A', value: `**${this.numberWithCommas(result.counts.A)}**`, inline: true }, { - name: "๐Ÿ… > A / Total plays", - value: `**${this.numberWithCommas(result.counts.SSH + result.counts.SH + result.counts.SS + result.counts.S + result.counts.A)}** (${(Math.round((((result.counts.SSH + result.counts.SH + result.counts.SS + result.counts.S + result.counts.A) / (result.counts.plays == 0 ? 1 : result.counts.plays)) + Number.EPSILON) * 10000) / 10000).toFixed(4)}) + name: '๐Ÿ… > A / Total plays', + value: `**${this.numberWithCommas( + result.counts.SSH + + result.counts.SH + + result.counts.SS + + result.counts.S + + result.counts.A + )}** (${( + Math.round( + ((result.counts.SSH + + result.counts.SH + + result.counts.SS + + result.counts.S + + result.counts.A) / + (result.counts.plays == 0 ? 1 : result.counts.plays) + + Number.EPSILON) * + 10000 + ) / 10000 + ).toFixed(4)}) \u200b`, inline: true }, { name: `โค Account Information`, - value: `Joined: , ` - }//, + value: `Joined: , ` + } //, /*{ name: `๐Ÿ’Œ Recent Events (Coming soon)`, value: `*How about we explore the area ahead of us later?*` @@ -199,106 +249,114 @@ export default class osu extends DiscordModule { embed.setAuthor({ name: `${result.name}'s osu profile`, url: `https://osu.ppy.sh/users/${result.id}`, - iconURL: 'https://upload.wikimedia.org/wikipedia/commons/e/e3/Osulogo.png' + iconURL: 'https://upload.wikimedia.org/wikipedia/commons/e/e3/Osulogo.png' }); // TODO: Fix for ppl with no image - embed.setThumbnail(`https://a.ppy.sh/${result.id}` || 'https://osu.ppy.sh/images/layout/avatar-guest.png'); + embed.setThumbnail( + `https://a.ppy.sh/${result.id}` || + 'https://osu.ppy.sh/images/layout/avatar-guest.png' + ); - const row = new MessageActionRow() - .addComponents( + const row = new MessageActionRow().addComponents( new MessageButton() .setEmoji('๐Ÿ”—') .setLabel(' Open Profile') .setURL(`https://osu.ppy.sh/users/${result.id}`) - .setStyle('LINK'), - ) + .setStyle('LINK') + ); - return await sendHybridInteractionMessageResponse(data, { embeds: [embed], components: [row] }); + return await sendHybridInteractionMessageResponse(data, { + embeds: [embed], + components: [row] + }); }, - beatmap: async(data: HybridInteractionMessage) => { - + beatmap: async (data: HybridInteractionMessage) => { let beatmap; - if(data.isMessage()) { - if(typeof args[1] === 'undefined') - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_BEATMAP_MENTIONED(data.getRaw())] }); + if (data.isMessage()) { + if (typeof args[1] === 'undefined') + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_BEATMAP_MENTIONED(data.getRaw())] + }); const [removed, ...newArgs] = args; - beatmap = newArgs.join(" "); - } - else if(data.isSlashCommand()) + beatmap = newArgs.join(' '); + } else if (data.isSlashCommand()) beatmap = data.getSlashCommand().options.getString('beatmap'); - - if(!validator.isNumeric(beatmap)) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_BEATMAP_ID_MENTIONED(data.getRaw())] }); + if (!validator.isNumeric(beatmap)) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.INVALID_BEATMAP_ID_MENTIONED(data.getRaw())] + }); let result = await osuAPI.client.getBeatmaps({ b: beatmap }); - if(result instanceof Array && result.length === 0) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_BEATMAP_FOUND(data.getRaw())] }); + if (result instanceof Array && result.length === 0) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.NO_BEATMAP_FOUND(data.getRaw())] + }); - if(data.isSlashCommand()) - await data.getSlashCommand().deferReply(); + if (data.isSlashCommand()) await data.getSlashCommand().deferReply(); const bm_result = result[0]; - - let url_mode = "#osu"; - let statusEmoji = "โšช"; + + let url_mode = '#osu'; + let statusEmoji = 'โšช'; let mode: unknown = bm_result.mode; let status: unknown = bm_result.approvalStatus; - if((mode as String) === "Taiko") - url_mode = "#taiko"; - else if((mode as String) === "Catch the Beat") - url_mode = "#fruits"; - else if((mode as String) === "Mania") - url_mode = "#mania"; + if ((mode as String) === 'Taiko') url_mode = '#taiko'; + else if ((mode as String) === 'Catch the Beat') url_mode = '#fruits'; + else if ((mode as String) === 'Mania') url_mode = '#mania'; - if((status as String) === "Ranked") - statusEmoji = "๐Ÿ†"; - else if((status as String) === "Loved") - statusEmoji = "โค"; - else if((status as String) === "Qualified") - statusEmoji = "โœ…"; - else if((status as String) === "WIP") - statusEmoji = "๐Ÿ› "; - else if((status as String) === "Pending") - statusEmoji = "โŒ›"; - else if((status as String) === "Graveyard") - statusEmoji = "๐Ÿ’€"; + if ((status as String) === 'Ranked') statusEmoji = '๐Ÿ†'; + else if ((status as String) === 'Loved') statusEmoji = 'โค'; + else if ((status as String) === 'Qualified') statusEmoji = 'โœ…'; + else if ((status as String) === 'WIP') statusEmoji = '๐Ÿ› '; + else if ((status as String) === 'Pending') statusEmoji = 'โŒ›'; + else if ((status as String) === 'Graveyard') statusEmoji = '๐Ÿ’€'; - const embed2 = makeInfoEmbed ({ + const embed2 = makeInfoEmbed({ icon: '', title: `${bm_result.title} - ${bm_result.artist}`, fields: [ { name: `Difficulty **[${bm_result.version}]**`, - value: `Mapper [${bm_result.creator}](${encodeURI('https://osu.ppy.sh/u/'+ bm_result.creator)}) + value: `Mapper [${bm_result.creator}](${encodeURI( + 'https://osu.ppy.sh/u/' + bm_result.creator + )}) Rating **${bm_result.rating.toFixed(2)}/10** - \u200b`, + \u200b` }, { - name: "โญ Star Difficulty", - value: `**${(Math.round((bm_result.difficulty.rating + Number.EPSILON) * 100) / 100).toFixed(2)}**`, + name: 'โญ Star Difficulty', + value: `**${( + Math.round((bm_result.difficulty.rating + Number.EPSILON) * 100) / + 100 + ).toFixed(2)}**`, inline: true }, { name: `โŒ› Length`, - value: `**${(Math.round(((bm_result.length.total / 60) + Number.EPSILON) * 100) / 100).toFixed(2).replace('.', ':')}**`, + value: `**${( + Math.round((bm_result.length.total / 60 + Number.EPSILON) * 100) / + 100 + ) + .toFixed(2) + .replace('.', ':')}**`, inline: true }, { - name: "๐Ÿ“ Combo", + name: '๐Ÿ“ Combo', value: `**${this.numberWithCommas(bm_result.maxCombo)}**`, inline: true }, { - name: "๐Ÿ•น Mode", + name: '๐Ÿ•น Mode', value: `**${mode}**`, inline: true }, { - name: "๐ŸŽต BPM", + name: '๐ŸŽต BPM', value: `**${bm_result.bpm}**`, inline: true }, @@ -309,17 +367,17 @@ export default class osu extends DiscordModule { inline: true }, { - name: "โญ• Circle", + name: 'โญ• Circle', value: `**${bm_result.objects.normal}**`, inline: true }, { - name: "๐Ÿ’จ Slider", + name: '๐Ÿ’จ Slider', value: `**${bm_result.objects.slider}**`, inline: true }, { - name: "๐Ÿ’ซ Spinner", + name: '๐Ÿ’ซ Spinner', value: `**${bm_result.objects.spinner}** \u200b`, inline: true @@ -328,30 +386,42 @@ export default class osu extends DiscordModule { name: `๐ŸŽถ Track Information`, value: `Language: **${bm_result.language}** Genre: **${bm_result.genre}** - Submission Date: , - Last updated: , - Approved: , - \u200b`, + Submission Date: , + Last updated: , + Approved: , + \u200b` }, { - name: "โ–ถ Plays", + name: 'โ–ถ Plays', value: `**${this.numberWithCommas(bm_result.counts.plays)}**`, inline: true }, { - name: "๐Ÿ Passes", + name: '๐Ÿ Passes', value: `**${this.numberWithCommas(bm_result.counts.passes)}**`, inline: true }, { - name: "โ™ฅ Favorites", + name: 'โ™ฅ Favorites', value: `**${this.numberWithCommas(bm_result.counts.favorites)}** \u200b`, inline: true }, { name: `๐Ÿ“Œ Tags`, - value: `\`\`${bm_result.tags.join(" ")}\`\``, + value: `\`\`${bm_result.tags.join(' ')}\`\`` } ], user: data.getUser() @@ -362,70 +432,78 @@ export default class osu extends DiscordModule { url: `https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}${url_mode}/${bm_result.id}`, iconURL: `https://upload.wikimedia.org/wikipedia/commons/e/e3/Osulogo.png` }); - embed2.setImage(`https://assets.ppy.sh/beatmaps/${bm_result.beatmapSetId}/covers/cover.jpg`); - + embed2.setImage( + `https://assets.ppy.sh/beatmaps/${bm_result.beatmapSetId}/covers/cover.jpg` + ); + const row = new MessageActionRow(); - if(bm_result.hasDownload) + if (bm_result.hasDownload) row.addComponents( new MessageButton() .setEmoji('๐ŸŒŽ') .setLabel(' Download (Beatconnect)') .setURL(`https://beatconnect.io/b/${bm_result.beatmapSetId}/`) - .setStyle('LINK'), - ) + .setStyle('LINK') + ); row.addComponents( new MessageButton() .setEmoji('๐Ÿ”—') .setLabel(' Open listing') - .setURL(`https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}${url_mode}/${bm_result.id}`) - .setStyle('LINK'), - ) + .setURL( + `https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}${url_mode}/${bm_result.id}` + ) + .setStyle('LINK') + ); row.addComponents( new MessageButton() .setEmoji('๐Ÿ’ฌ') .setLabel(' Open discussion') - .setURL(`https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}/discussion`) - .setStyle('LINK'), - ) - - return await sendHybridInteractionMessageResponse(data, { embeds: [embed2], components: [row] }); + .setURL( + `https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}/discussion` + ) + .setStyle('LINK') + ); + + return await sendHybridInteractionMessageResponse(data, { + embeds: [embed2], + components: [row] + }); } - } + }; let query; - if(data.isMessage()) { - if(args.length === 0) { - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.osu_INFO(data.getRaw())] }); + if (data.isMessage()) { + if (args.length === 0) { + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.osu_INFO(data.getRaw())] + }); } query = args[0].toLowerCase(); - } - else if(data.isSlashCommand()) { + } else if (data.isSlashCommand()) { query = args.getSubcommand(); } - switch(query) { - case "user": - case "u": + switch (query) { + case 'user': + case 'u': return await funct.user(data); - case "beatmap": - case "b": + case 'beatmap': + case 'b': return await funct.beatmap(data); } - } private numberWithCommas(x: Number) { try { - return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); - } catch(err) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); + } catch (err) { return x; } } // Criteria from https://github.com/ppy/osu-web/blob/9de00a0b874c56893d98261d558d78d76259d81b/app/Libraries/UsernameValidation.php private validate_osu_username(username: string) { - //username_no_spaces if (username.startsWith(' ') || username.endsWith(' ')) return false; @@ -436,12 +514,11 @@ export default class osu extends DiscordModule { if (username.length > 15) return false; //username_invalid_characters - if (username.includes(' ') || !(/^[A-Za-z0-9-\[\]_ ]+$/.test(username))) return false; + if (username.includes(' ') || !/^[A-Za-z0-9-\[\]_ ]+$/.test(username)) return false; //username_no_space_userscore_mix if (username.includes('_') && username.includes(' ')) return false; return true; } - -} \ No newline at end of file +} diff --git a/src/exception/Errors.ts b/src/exception/Errors.ts index d8db263..83b59ff 100644 --- a/src/exception/Errors.ts +++ b/src/exception/Errors.ts @@ -1,19 +1,13 @@ -import { CustomError } from 'ts-custom-error' - +import { CustomError } from 'ts-custom-error'; export class ServiceError extends CustomError { - public constructor( - public statusCode: number, - message: string - ) { - super(message) + public constructor(public statusCode: number, message: string) { + super(message); } } export class DatabaseError extends CustomError { - public constructor( - message: string - ) { - super(message) + public constructor(message: string) { + super(message); } -} \ No newline at end of file +} diff --git a/src/exception/NativeException.ts b/src/exception/NativeException.ts index 0587b3f..4ca50b5 100644 --- a/src/exception/NativeException.ts +++ b/src/exception/NativeException.ts @@ -1,12 +1,8 @@ import Logger from '../libs/Logger'; -import App from '../providers/App'; - class NativeException { - - public process (): void { - - process.on('uncaughtException', exception => { + public process(): void { + process.on('uncaughtException', (exception) => { Logger.log('critical', 'Critical error, cleaning up and exiting'); Logger.log('critical', exception.stack); @@ -14,11 +10,10 @@ class NativeException { process.exit(1); }); - process.on('unhandledRejection', exception => { + process.on('unhandledRejection', (exception) => { throw exception; }); - } } -export default new NativeException; \ No newline at end of file +export default new NativeException(); diff --git a/src/index.ts b/src/index.ts index abee3b9..00bddf0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,4 +9,4 @@ App.loadPrisma(); App.loadDiscord(); App.load_osu(); -export default App; \ No newline at end of file +export default App; diff --git a/src/libs/Logger.ts b/src/libs/Logger.ts index 135dfca..1765851 100644 --- a/src/libs/Logger.ts +++ b/src/libs/Logger.ts @@ -7,7 +7,7 @@ const levels = { warn: 3, info: 4, http: 5, - debug: 6, + debug: 6 }; const level = () => { @@ -23,7 +23,7 @@ const colors = { warn: 'yellow', info: 'green', http: 'magenta', - debug: 'white', + debug: 'white' }; winston.addColors(colors); @@ -31,25 +31,23 @@ winston.addColors(colors); const format = winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }), winston.format.colorize({ all: true }), - winston.format.printf( - (info) => `[${info.timestamp}] [${info.level}] ${info.message}` - ) + winston.format.printf((info) => `[${info.timestamp}] [${info.level}] ${info.message}`) ); const transports = [ new winston.transports.Console(), new winston.transports.File({ filename: 'logs/error.log', - level: 'error', + level: 'error' }), - new winston.transports.File({ filename: 'logs/all.log' }), + new winston.transports.File({ filename: 'logs/all.log' }) ]; const Logger = winston.createLogger({ level: level(), levels, format, - transports, + transports }); -export default Logger; \ No newline at end of file +export default Logger; diff --git a/src/providers/App.ts b/src/providers/App.ts index f508ad2..7cd4d8f 100644 --- a/src/providers/App.ts +++ b/src/providers/App.ts @@ -1,15 +1,15 @@ -import Logger from '../libs/Logger'; - import Environment from './Environment'; +import Configuration from './Configuration'; import Prisma from './Prisma'; import Discord from './Discord'; import osu from './osuAPI'; -import Configuration from './Configuration'; +import Logger from '../libs/Logger'; class App { - public readonly versionNumber = `0.09`; - public readonly version = `${this.versionNumber}${Environment.get().NODE_ENV === "development" ? ' / Development Build' : ''}`; + public readonly version = `${this.versionNumber}${ + Environment.get().NODE_ENV === 'development' ? ' / Development Build' : '' + }`; public loadConfig(): void { Logger.log('info', 'Loading configuration'); @@ -37,4 +37,4 @@ class App { } } -export default new App; \ No newline at end of file +export default new App(); diff --git a/src/providers/Cache.ts b/src/providers/Cache.ts index 8b4f43f..0ebb40f 100644 --- a/src/providers/Cache.ts +++ b/src/providers/Cache.ts @@ -1,30 +1,27 @@ -import { Guild } from "@prisma/client"; -import { Snowflake } from "discord-api-types/v10"; -import Prisma from "./Prisma"; +import { Guild } from '@prisma/client'; +import { Snowflake } from 'discord-api-types/v10'; +import Prisma from './Prisma'; class Cache { - private cache: any; - constructor () { + constructor() { this.cache = { - Guilds: { - - } + Guilds: {} }; } public async updateGuildsCache() { const Guilds = await Prisma.client.guild.findMany(); - for(let Guild of Guilds) { + for (let Guild of Guilds) { this.setGuildData(Guild.id, Guild); } } public async updateGuildCache(guildID: Snowflake) { - const DBGuild = await Prisma.client.guild.findFirst({ where:{id: guildID} }); - - if(DBGuild === null) return; + const DBGuild = await Prisma.client.guild.findFirst({ where: { id: guildID } }); + + if (DBGuild === null) return; this.setGuildData(guildID, DBGuild); } @@ -32,9 +29,8 @@ class Cache { this.cache.Guilds[id] = data; } - public async getGuild(id: string): Promise<(Guild | undefined)> { - if(typeof this.cache.Guilds[id] !== 'undefined') - return this.cache.Guilds[id]; + public async getGuild(id: string): Promise { + if (typeof this.cache.Guilds[id] !== 'undefined') return this.cache.Guilds[id]; const Guild = await Prisma.client.guild.findFirst({ where: { @@ -42,18 +38,15 @@ class Cache { } }); - if(Guild === null) - return undefined; + if (Guild === null) return undefined; this.setGuildData(Guild.id, Guild); return this.cache.Guilds[id]; - } public getGuilds(): void { return this.cache.Guilds; } - } -export default new Cache(); \ No newline at end of file +export default new Cache(); diff --git a/src/providers/Configuration.ts b/src/providers/Configuration.ts index 55331be..975592f 100644 --- a/src/providers/Configuration.ts +++ b/src/providers/Configuration.ts @@ -1,48 +1,50 @@ -import fs from "fs"; -import path from "path"; +import fs from 'fs'; +import path from 'path'; const ConfigurationData: any = []; class Configuration { - public init(): void { const dir = path.join(process.cwd(), 'configs/'); if (!fs.existsSync(dir)) { fs.mkdirSync(dir); } - this.copyExampleIfNotExists("Ping.json"); - this.copyExampleIfNotExists("ServiceAnnouncement.json"); + this.copyExampleIfNotExists('Ping.json'); + this.copyExampleIfNotExists('ServiceAnnouncement.json'); - this.loadConfig("Ping.json"); - this.loadConfig("ServiceAnnouncement.json"); + this.loadConfig('Ping.json'); + this.loadConfig('ServiceAnnouncement.json'); } public loadConfig(configFileName: string): void { const dir = path.join(process.cwd(), 'configs/'); - if (!fs.existsSync(path.join(dir, configFileName))) + if (!fs.existsSync(path.join(dir, configFileName))) throw new Error(`Config file ${configFileName} does not exist`); const config = JSON.parse(fs.readFileSync(path.join(dir, configFileName)).toString()); - ConfigurationData[configFileName.replace(/\.[^/.]+$/, "")] = config; + ConfigurationData[configFileName.replace(/\.[^/.]+$/, '')] = config; } public getConfig(key?: string) { - if(!key) - return ConfigurationData; + if (!key) return ConfigurationData; else { - if(ConfigurationData[key]) - return ConfigurationData[key]; - else - throw new Error(`No configuration found for ${key}`); + if (ConfigurationData[key]) return ConfigurationData[key]; + else throw new Error(`No configuration found for ${key}`); } } private copyExampleIfNotExists(file: string): void { const dir = path.join(process.cwd(), 'configs/'); if (!fs.existsSync(path.join(dir, file))) { - fs.copyFileSync(path.join(process.cwd(), 'configs_example/', `${file.replace('.json', '.example.json')}`), path.join(dir, file)); + fs.copyFileSync( + path.join( + process.cwd(), + 'configs_example/', + `${file.replace('.json', '.example.json')}` + ), + path.join(dir, file) + ); } } - } export default new Configuration(); diff --git a/src/providers/Discord.ts b/src/providers/Discord.ts index bf18e29..ee0cdf9 100644 --- a/src/providers/Discord.ts +++ b/src/providers/Discord.ts @@ -1,56 +1,59 @@ -import { Guild, Client, GuildMember, Intents, Interaction, Message, TextChannel} from "discord.js"; -import { Guild as GuildPrisma } from ".prisma/client"; +import { Guild, Client, GuildMember, Intents, Interaction, Message, TextChannel } from 'discord.js'; -import Logger from "../libs/Logger"; -import Environment from "./Environment"; +import Logger from '../libs/Logger'; +import Environment from './Environment'; -import Discord_Core from "../discord/Core"; -import Discord_Settings from "../discord/Settings"; -import Discord_Ping from "../discord/Ping"; -import Discord_Help from "../discord/Help"; -import Discord_Invite from "../discord/Invite"; -import Discord_Say from "../discord/Say"; -import Discord_InteractionManager from "../discord/InteractionManager"; -import Discord_MembershipScreening from "../discord/MembershipScreening"; -import Discord_osu from "../discord/osu"; -import Discord_UserInfo from "../discord/UserInfo"; -import Discord_Stats from "../discord/Stats"; +import Discord_Core from '../discord/Core'; +import Discord_Settings from '../discord/Settings'; +import Discord_Ping from '../discord/Ping'; +import Discord_Help from '../discord/Help'; +import Discord_Invite from '../discord/Invite'; +import Discord_Say from '../discord/Say'; +import Discord_InteractionManager from '../discord/InteractionManager'; +import Discord_MembershipScreening from '../discord/MembershipScreening'; +import Discord_osu from '../discord/osu'; +import Discord_UserInfo from '../discord/UserInfo'; +import Discord_Stats from '../discord/Stats'; -import Discord_MusicPlayer_Play from "../discord/MusicPlayer/Play"; -import Discord_MusicPlayer_Skip from "../discord/MusicPlayer/Skip"; -import Discord_MusicPlayer_Join from "../discord/MusicPlayer/Join"; -import Discord_MusicPlayer_Leave from "../discord/MusicPlayer/Leave"; -import Discord_MusicPlayer_Queue from "../discord/MusicPlayer/Queue"; -import Discord_MusicPlayer_Search from "../discord/MusicPlayer/Search"; -import Discord_MusicPlayer_NowPlaying from "../discord/MusicPlayer/NowPlaying"; -import Discord_MusicPlayer_Loop from "../discord/MusicPlayer/Loop"; -import Discord_MusicPlayer_Pause from "../discord/MusicPlayer/Pause"; -import Discord_MusicPlayer_Resume from "../discord/MusicPlayer/Resume"; +import Discord_MusicPlayer_Play from '../discord/MusicPlayer/Play'; +import Discord_MusicPlayer_Skip from '../discord/MusicPlayer/Skip'; +import Discord_MusicPlayer_Join from '../discord/MusicPlayer/Join'; +import Discord_MusicPlayer_Leave from '../discord/MusicPlayer/Leave'; +import Discord_MusicPlayer_Queue from '../discord/MusicPlayer/Queue'; +import Discord_MusicPlayer_Search from '../discord/MusicPlayer/Search'; +import Discord_MusicPlayer_NowPlaying from '../discord/MusicPlayer/NowPlaying'; +import Discord_MusicPlayer_Loop from '../discord/MusicPlayer/Loop'; +import Discord_MusicPlayer_Pause from '../discord/MusicPlayer/Pause'; +import Discord_MusicPlayer_Resume from '../discord/MusicPlayer/Resume'; -import Discord_Developer_ServiceAnnouncement from "../discord/developer/ServiceAnnouncement"; -import Discord_Developer_Debug from "../discord/developer/Debug"; +import Discord_Developer_ServiceAnnouncement from '../discord/developer/ServiceAnnouncement'; +import Discord_Developer_Debug from '../discord/developer/Debug'; -import Cache from "./Cache"; -import DiscordModule from "../utils/DiscordModule"; -import { Map } from "typescript"; +import Cache from './Cache'; +import DiscordModule from '../utils/DiscordModule'; +import { Map } from 'typescript'; class Discord { - public client: Client; private loaded_module = new Map(); - constructor () { - this.client = new Client({ + constructor() { + this.client = new Client({ //partials: ['MESSAGE', 'CHANNEL', 'REACTION'], - intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_MEMBERS, Intents.FLAGS.GUILD_PRESENCES, Intents.FLAGS.GUILD_VOICE_STATES] + intents: [ + Intents.FLAGS.GUILDS, + Intents.FLAGS.GUILD_MESSAGES, + Intents.FLAGS.GUILD_MEMBERS, + Intents.FLAGS.GUILD_PRESENCES, + Intents.FLAGS.GUILD_VOICE_STATES + ] }); } public init(): void { - Logger.info('Logging in to discord'); this.client.login(Environment.get().DISCORD_TOKEN); - + const modules: DiscordModule[] = [ new Discord_Core(), new Discord_Help(), @@ -80,191 +83,226 @@ class Discord { new Discord_Developer_Debug() ]; - for(const _module of modules) { - if(_module.id) { - if(this.loaded_module.has(_module.id)) - Logger.error(`Module ${_module.constructor.name} is trying to assign a conflicting module id ${_module.id}. ${this.loaded_module.get(_module.id)!.constructor.name} is already assigned to this id.`); - else - this.loaded_module.set(_module.id, _module); - } - else - Logger.error(`Invalid module ${_module.constructor.name}. The module does not have an id.`); + for (const _module of modules) { + if (_module.id) { + if (this.loaded_module.has(_module.id)) + Logger.error( + `Module ${ + _module.constructor.name + } is trying to assign a conflicting module id ${_module.id}. ${ + this.loaded_module.get(_module.id)!.constructor.name + } is already assigned to this id.` + ); + else this.loaded_module.set(_module.id, _module); + } else + Logger.error( + `Invalid module ${_module.constructor.name}. The module does not have an id.` + ); } Logger.info(`Loaded ${this.loaded_module.size} Discord Modules`); - for(const module of this.loaded_module) { + for (const module of this.loaded_module) { let thisModule: DiscordModule = module[1]; thisModule.Init(); } // On bot logged in - this.client.on("ready", () => { - for(const module of this.loaded_module) { + this.client.on('ready', () => { + for (const module of this.loaded_module) { let thisModule: DiscordModule = module[1]; thisModule.Ready(); } }); // Member join guild event to modules - this.client.on("guildMemberAdd", (member: GuildMember) => { - for(const module of this.loaded_module) { + this.client.on('guildMemberAdd', (member: GuildMember) => { + for (const module of this.loaded_module) { let thisModule: DiscordModule = module[1]; thisModule.GuildMemberAdd(member); } }); // Interaction create event to modules - this.client.on("interactionCreate", (interaction: Interaction) => { - for(const module of this.loaded_module) { + this.client.on('interactionCreate', (interaction: Interaction) => { + for (const module of this.loaded_module) { let thisModule: DiscordModule = module[1]; - - if(interaction.guild) { + + if (interaction.guild) { thisModule.GuildInteractionCreate(interaction); - if(interaction.isCommand() && interaction.commandName && thisModule.commandInteractionName) { + if ( + interaction.isCommand() && + interaction.commandName && + thisModule.commandInteractionName + ) { thisModule.GuildCommandInteractionCreate(interaction); - if(interaction.commandName.toLowerCase() === thisModule.commandInteractionName) + if ( + interaction.commandName.toLowerCase() === + thisModule.commandInteractionName + ) thisModule.GuildModuleCommandInteractionCreate(interaction); - } - else if(interaction.isButton()) { + } else if (interaction.isButton()) { thisModule.GuildButtonInteractionCreate(interaction); - } - else if(interaction.isSelectMenu()) { + } else if (interaction.isSelectMenu()) { thisModule.GuildSelectMenuInteractionCreate(interaction); } } - + //thisModule.InteractionCreate(interaction); } }); // Message create event to modules - this.client.on("messageCreate", (message: Message) => { - for(const module of this.loaded_module) { + this.client.on('messageCreate', (message: Message) => { + for (const module of this.loaded_module) { let thisModule: DiscordModule = module[1]; thisModule.GuildMessageCreate(message); } }); // Joined guild event to modules - this.client.on("guildCreate", (guild: Guild) => { - for(const module of this.loaded_module) { + this.client.on('guildCreate', (guild: Guild) => { + for (const module of this.loaded_module) { let thisModule: DiscordModule = module[1]; thisModule.GuildCreate(guild); } }); // Handling guild commands - this.client.on("messageCreate", async (message: Message) => { - - if(!(message.channel instanceof TextChannel)) return; - if(message.author.bot) return; - if(typeof message.guild?.id === 'undefined') return; + this.client.on('messageCreate', async (message: Message) => { + if (!(message.channel instanceof TextChannel)) return; + if (message.author.bot) return; + if (typeof message.guild?.id === 'undefined') return; let GuildCache = await Cache.getGuild(message.guild.id); - if(typeof GuildCache === 'undefined' || typeof GuildCache.prefix === 'undefined') return; + if (typeof GuildCache === 'undefined' || typeof GuildCache.prefix === 'undefined') + return; - if(!message.content.startsWith(GuildCache.prefix)) return; + if (!message.content.startsWith(GuildCache.prefix)) return; let noPrefixMessage = message.content.replace(GuildCache.prefix, ''); let symbols = [ - '!','@','#','$','%','^','&','*','(',')','-','=','_','+','\\','/','<','>','[',']','{','}','`','"',"'",',','.','~','|',';',':','?','ใ€','ใ€‚' + '!', + '@', + '#', + '$', + '%', + '^', + '&', + '*', + '(', + ')', + '-', + '=', + '_', + '+', + '\\', + '/', + '<', + '>', + '[', + ']', + '{', + '}', + '`', + '"', + "'", + ',', + '.', + '~', + '|', + ';', + ':', + '?', + 'ใ€', + 'ใ€‚' ]; const isTag = (prefix: string) => { - return prefix.startsWith('<@!') && prefix.endsWith('>') || - prefix.startsWith('<:') && prefix.endsWith('>') || - prefix.startsWith('') || - prefix.startsWith('<#') && prefix.endsWith('>'); - } + return ( + (prefix.startsWith('<@!') && prefix.endsWith('>')) || + (prefix.startsWith('<:') && prefix.endsWith('>')) || + (prefix.startsWith('')) || + (prefix.startsWith('<#') && prefix.endsWith('>')) + ); + }; - if((GuildCache.prefix.indexOf(' ') >= 0)) { - if(noPrefixMessage.charAt(0) !== ' ') return; - } - else { - if(symbols.includes(GuildCache.prefix.charAt(GuildCache.prefix.length - 1))) { - - if(noPrefixMessage.charAt(0) === ' ') { + if (GuildCache.prefix.indexOf(' ') >= 0) { + if (noPrefixMessage.charAt(0) !== ' ') return; + } else { + if (symbols.includes(GuildCache.prefix.charAt(GuildCache.prefix.length - 1))) { + if (noPrefixMessage.charAt(0) === ' ') { //Handle for "@Bot " - if(isTag(GuildCache.prefix)) {} - else - return; - } - else { + if (isTag(GuildCache.prefix)) { + } else return; + } else { //Handle for "@Bot" - if(isTag(GuildCache.prefix)) return; + if (isTag(GuildCache.prefix)) return; } - } - - else { - if(noPrefixMessage.charAt(0) !== ' ') return; + } else { + if (noPrefixMessage.charAt(0) !== ' ') return; } //if(noPrefixMessage.charAt(0) !== ' ' && !symbols.includes(noPrefixMessage.charAt(0))) return; } - if(noPrefixMessage === '') return; - if(noPrefixMessage.charAt(0) === ' ') { + if (noPrefixMessage === '') return; + if (noPrefixMessage.charAt(0) === ' ') { /*if(symbols.includes(GuildCache.prefix.charAt(GuildCache.prefix.length - 1))) { if((GuildCache.prefix.indexOf(' ') >= 0)) return; }*/ - + noPrefixMessage = noPrefixMessage.substring(1); } - let args = noPrefixMessage.split(" "); - args = args.filter(e => e !== ''); + let args = noPrefixMessage.split(' '); + args = args.filter((e) => e !== ''); let command = args[0]; args.shift(); - if(args.length === 0) - args = []; + if (args.length === 0) args = []; - for(const module of this.loaded_module) { + for (const module of this.loaded_module) { let thisModule: DiscordModule = module[1]; thisModule.GuildOnCommand(command, args, message); - - if(thisModule.commands && thisModule.commands.includes(command)) + + if (thisModule.commands && thisModule.commands.includes(command)) thisModule.GuildOnModuleCommand(args, message); } }); // Handling mentions - this.client.on("messageCreate", async (message: Message) => { - + this.client.on('messageCreate', async (message: Message) => { // TODO: Handle DMs commands soon - if(!(message.channel instanceof TextChannel)) return; - if(message.author.bot) return; + if (!(message.channel instanceof TextChannel)) return; + if (message.author.bot) return; - if(typeof message.guild?.id === 'undefined') return; - if(!message.mentions.users) return; + if (typeof message.guild?.id === 'undefined') return; + if (!message.mentions.users) return; - if(message.mentions.users.first()?.id !== this.client.user?.id) return; - if(!message.content.startsWith(`<@!${this.client.user?.id}>`)) return; + if (message.mentions.users.first()?.id !== this.client.user?.id) return; + if (!message.content.startsWith(`<@!${this.client.user?.id}>`)) return; - let args = message.content.split(" "); + let args = message.content.split(' '); let command = args[1]; args.shift(); args.shift(); - args = args.filter(e => e !== ''); + args = args.filter((e) => e !== ''); - if(args.length === 0) - args = []; + if (args.length === 0) args = []; - for(const module of this.loaded_module) { + for (const module of this.loaded_module) { let thisModule: DiscordModule = module[1]; thisModule.GuildOnCommand(command, args, message); - - if(thisModule.commands && thisModule.commands.includes(command)) + + if (thisModule.commands && thisModule.commands.includes(command)) thisModule.GuildOnModuleCommand(args, message); } }); - } - } export default new Discord(); diff --git a/src/providers/DiscordMusicPlayer.ts b/src/providers/DiscordMusicPlayer.ts index 48edaf4..31ab342 100644 --- a/src/providers/DiscordMusicPlayer.ts +++ b/src/providers/DiscordMusicPlayer.ts @@ -1,10 +1,23 @@ -import playdl, { YouTubeVideo } from "play-dl"; -import { VoiceChannel, Snowflake, TextChannel, StageChannel, Guild } from "discord.js"; -import { AudioPlayer, VoiceConnection, createAudioPlayer, joinVoiceChannel, createAudioResource, VoiceConnectionStatus, AudioPlayerStatus, AudioPlayerState, NoSubscriberBehavior, VoiceConnectionState, AudioPlayerError, DiscordGatewayAdapterCreator } from "@discordjs/voice"; -import { EventEmitter } from "stream"; +import { VoiceChannel, Snowflake, TextChannel, StageChannel, Guild } from 'discord.js'; +import { + AudioPlayer, + VoiceConnection, + createAudioPlayer, + joinVoiceChannel, + createAudioResource, + VoiceConnectionStatus, + AudioPlayerStatus, + AudioPlayerState, + NoSubscriberBehavior, + VoiceConnectionState, + AudioPlayerError, + DiscordGatewayAdapterCreator +} from '@discordjs/voice'; +import playdl, { YouTubeVideo } from 'play-dl'; +import { EventEmitter } from 'stream'; -import DiscordProvider from "./Discord"; -import Environment from "./Environment"; +import DiscordProvider from './Discord'; +import Environment from './Environment'; export type ValidTracks = YouTubeVideo; @@ -13,10 +26,10 @@ if (Environment.get().YOUTUBE_COOKIE_BASE64) { youtube: { cookie: Buffer.from(Environment.get().YOUTUBE_COOKIE_BASE64, 'base64').toString() } - }) + }); } export class Queue { - public track: (ValidTracks)[] = []; + public track: ValidTracks[] = []; } export class YouTubeLink { @@ -56,14 +69,14 @@ export class VoiceDisconnectedEvent { } export enum DiscordMusicPlayerLoopMode { - None = "none", - Current = "current" + None = 'none', + Current = 'current' } export class DiscordMusicPlayerInstance { public queue: Queue; public player: AudioPlayer; public textChannel?: TextChannel; - public voiceChannel: (VoiceChannel | StageChannel); + public voiceChannel: VoiceChannel | StageChannel; public voiceConnection?: VoiceConnection; public previousTrack?: ValidTracks; @@ -72,7 +85,7 @@ export class DiscordMusicPlayerInstance { public readonly events: EventEmitter; - constructor({ voiceChannel }: { voiceChannel: (VoiceChannel | StageChannel) }) { + constructor({ voiceChannel }: { voiceChannel: VoiceChannel | StageChannel }) { this.queue = new Queue(); this.player = createAudioPlayer({ behaviors: { @@ -85,8 +98,10 @@ export class DiscordMusicPlayerInstance { this.player.on(AudioPlayerStatus.Idle, async (oldStage, newStage) => { //The player stopped - if (newStage.status === AudioPlayerStatus.Idle && oldStage.status !== AudioPlayerStatus.Idle) { - + if ( + newStage.status === AudioPlayerStatus.Idle && + oldStage.status !== AudioPlayerStatus.Idle + ) { // Loop mode is set to current song if (this.loopMode === DiscordMusicPlayerLoopMode.Current) { if (this.queue.track.length !== 0) { @@ -99,14 +114,12 @@ export class DiscordMusicPlayerInstance { // There are more songs in the queue, remove finished song and play the next one if (this.queue.track.length !== 0) { let previousTrack = this.queue.track.shift(); - if(previousTrack) - this.previousTrack = previousTrack; + if (previousTrack) this.previousTrack = previousTrack; if (this.queue.track.length > 0) { this.playTrack(this.queue.track[0]); } } - } }); @@ -133,40 +146,49 @@ export class DiscordMusicPlayerInstance { return true; } - public joinVoiceChannel(voiceChannel: (VoiceChannel | StageChannel), textChannel?: TextChannel) { + public joinVoiceChannel(voiceChannel: VoiceChannel | StageChannel, textChannel?: TextChannel) { const permissions = voiceChannel.permissionsFor(DiscordProvider.client.user!); - if (!permissions || !voiceChannel.joinable || !permissions.has("CONNECT")) - throw new Error("No permissions"); + if (!permissions || !voiceChannel.joinable || !permissions.has('CONNECT')) + throw new Error('No permissions'); - if (textChannel) - this.textChannel = textChannel; + if (textChannel) this.textChannel = textChannel; this.voiceConnection = joinVoiceChannel({ channelId: this.voiceChannel.id, guildId: this.voiceChannel.guild.id, - adapterCreator: this.voiceChannel.guild.voiceAdapterCreator as DiscordGatewayAdapterCreator + adapterCreator: this.voiceChannel.guild + .voiceAdapterCreator as DiscordGatewayAdapterCreator }); - this.voiceConnection.on(VoiceConnectionStatus.Ready, (oldState: VoiceConnectionState, newState: VoiceConnectionState) => { - let currentVC = DiscordProvider.client.guilds.cache.get(voiceChannel.guild.id)?.me?.voice.channel; - if (currentVC && currentVC.id !== this.voiceChannel.id) { - this.voiceChannel = currentVC; - } - }); - - this.voiceConnection.on(VoiceConnectionStatus.Disconnected, (oldState: VoiceConnectionState, newState: VoiceConnectionState) => { - setTimeout(() => { - if (!DiscordProvider.client.guilds.cache.get(voiceChannel.guildId!)!.me!.voice.channelId) { - this.events.emit('disconnect', new VoiceDisconnectedEvent(this)); + this.voiceConnection.on( + VoiceConnectionStatus.Ready, + (oldState: VoiceConnectionState, newState: VoiceConnectionState) => { + let currentVC = DiscordProvider.client.guilds.cache.get(voiceChannel.guild.id)?.me + ?.voice.channel; + if (currentVC && currentVC.id !== this.voiceChannel.id) { + this.voiceChannel = currentVC; } - }, 1000); - }); + } + ); + + this.voiceConnection.on( + VoiceConnectionStatus.Disconnected, + (oldState: VoiceConnectionState, newState: VoiceConnectionState) => { + setTimeout(() => { + if ( + !DiscordProvider.client.guilds.cache.get(voiceChannel.guildId!)!.me!.voice + .channelId + ) { + this.events.emit('disconnect', new VoiceDisconnectedEvent(this)); + } + }, 1000); + } + ); } public async leaveVoiceChannel() { - if (this.player) - this.player.pause(); + if (this.player) this.player.pause(); if (DiscordProvider.client.guilds.cache.get(this.voiceChannel.guild.id)?.me?.voice) { this.voiceConnection?.disconnect(); @@ -174,18 +196,18 @@ export class DiscordMusicPlayerInstance { } public async pausePlayer() { - if(this.paused || !this.player) return; - if(!this.player.pause(true)) throw new Error('Unable to pause player'); + if (this.paused || !this.player) return; + if (!this.player.pause(true)) throw new Error('Unable to pause player'); this.paused = true; } public async resumePlayer() { - if(!this.paused || !this.player) return; - if(!this.player.unpause()) throw new Error('Unable to resume player'); + if (!this.paused || !this.player) return; + if (!this.player.unpause()) throw new Error('Unable to resume player'); this.paused = false; } - public addTrackToQueue(track: (ValidTracks)) { + public addTrackToQueue(track: ValidTracks) { if (this.queue.track.length === 0) { this.queue.track.push(track); this.playTrack(this.queue.track[0]); @@ -196,16 +218,16 @@ export class DiscordMusicPlayerInstance { } public async playTrack(track: ValidTracks) { - if (!this.voiceConnection) throw new Error("No voice connection"); - + if (!this.voiceConnection) throw new Error('No voice connection'); + try { const stream = await playdl.stream(track.url); const resource = createAudioResource(stream.stream, { inputType: stream.type }); - - this.player.play(resource) - this.voiceConnection.subscribe(this.player) + + this.player.play(resource); + this.voiceConnection.subscribe(this.player); } catch (error: any) { this.events.emit('error', new PlayerErrorEvent(this, error)); this.skipTrack(); @@ -213,14 +235,13 @@ export class DiscordMusicPlayerInstance { } public async skipTrack() { - if (!this.voiceConnection) throw new Error("No voice connection"); + if (!this.voiceConnection) throw new Error('No voice connection'); if (this.queue.track.length > 1) { this.previousTrack = this.queue.track[0]; this.queue.track.shift(); this.playTrack(this.queue.track[0]); - } - else { + } else { this.previousTrack = this.queue.track[0]; this.queue.track.shift(); this.player.stop(); @@ -248,8 +269,7 @@ export class DiscordMusicPlayerInstance { if (this.voiceConnection) { this.voiceConnection.removeAllListeners(); - if (this.voiceConnection.state.status !== 'destroyed') - this.voiceConnection.destroy(); + if (this.voiceConnection.state.status !== 'destroyed') this.voiceConnection.destroy(); } if (this.player) { @@ -266,16 +286,17 @@ export class DiscordMusicPlayerInstance { const stream = 'https://fakestream:42069/fake/stream/fake/audio/fake.mp3'; const resource = createAudioResource(stream); this.player.play(resource); - this.player.emit('error', new AudioPlayerError(new Error("Music player was manually crashed"), null!)); + this.player.emit( + 'error', + new AudioPlayerError(new Error('Music player was manually crashed'), null!) + ); } - } class DiscordMusicPlayer { - public GuildQueue = new Map(); - public getGuildInstance(guildId: Snowflake): (DiscordMusicPlayerInstance | null) { + public getGuildInstance(guildId: Snowflake): DiscordMusicPlayerInstance | null { if (!this.isGuildInstanceExists(guildId)) return null; return this.GuildQueue.get(guildId); } @@ -284,12 +305,11 @@ class DiscordMusicPlayer { return this.GuildQueue.has(guildId); } - public createGuildInstance(guildId: Snowflake, voiceChannel: (VoiceChannel | StageChannel)) { + public createGuildInstance(guildId: Snowflake, voiceChannel: VoiceChannel | StageChannel) { this.GuildQueue.set(guildId, new DiscordMusicPlayerInstance({ voiceChannel })); } - public async destoryGuildInstance(guild: (Guild | Snowflake)) { - + public async destoryGuildInstance(guild: Guild | Snowflake) { let guildId: Snowflake = guild instanceof Guild ? guild.id : guild; if (this.isGuildInstanceExists(guildId)) { @@ -299,39 +319,48 @@ class DiscordMusicPlayer { } public async searchYouTubeByQuery(query: string) { - const searched: YouTubeVideo[] = await playdl.search(query, { source: { youtube: "video" } }); + const searched: YouTubeVideo[] = await playdl.search(query, { + source: { youtube: 'video' } + }); if (searched.length == 0) return null; return searched; } public async searchYouTubeByYouTubeLink(youtubeLink: YouTubeLink) { - // Search the url - const searched: YouTubeVideo[] = await playdl.search("https://www.youtube.com/watch?v=" + youtubeLink.videoId, { source: { youtube: "video" } }); + const searched: YouTubeVideo[] = await playdl.search( + 'https://www.youtube.com/watch?v=' + youtubeLink.videoId, + { source: { youtube: 'video' } } + ); for (let video of searched) { - if (video.id === youtubeLink.videoId) - return video; + if (video.id === youtubeLink.videoId) return video; } // Serch the video Id - const searched2: YouTubeVideo[] = await playdl.search(youtubeLink.videoId, { source: { youtube: "video" } }); + const searched2: YouTubeVideo[] = await playdl.search(youtubeLink.videoId, { + source: { youtube: 'video' } + }); for (let video of searched2) { - if (video.id === youtubeLink.videoId) - return video; + if (video.id === youtubeLink.videoId) return video; } // Last resort, search the title - const videoInfo = await playdl.video_basic_info("https://www.youtube.com/watch?v=" + youtubeLink.videoId); + const videoInfo = await playdl.video_basic_info( + 'https://www.youtube.com/watch?v=' + youtubeLink.videoId + ); if (videoInfo?.video_details?.title) { - const searched: YouTubeVideo[] = await playdl.search(videoInfo.video_details.title, { source: { youtube: "video" } }); + const searched: YouTubeVideo[] = await playdl.search(videoInfo.video_details.title, { + source: { youtube: 'video' } + }); for (let video of searched) { - if (video.id === youtubeLink.videoId) - return video; + if (video.id === youtubeLink.videoId) return video; } } - let yt_info = await playdl.video_info("https://www.youtube.com/watch?v=" + youtubeLink.videoId); - if(yt_info) { + let yt_info = await playdl.video_info( + 'https://www.youtube.com/watch?v=' + youtubeLink.videoId + ); + if (yt_info) { return new YouTubeVideo({ id: yt_info.video_details.id, url: yt_info.video_details.url, @@ -341,7 +370,7 @@ class DiscordMusicPlayer { durationRaw: yt_info.video_details.durationRaw, durationInSec: yt_info.video_details.durationInSec, uploadedAt: yt_info.video_details.uploadedAt, - upcoming: yt_info.video_details.upcoming, + upcoming: yt_info.video_details.upcoming, views: yt_info.video_details.views, thumbnails: yt_info.video_details.thumbnails, channel: yt_info.video_details.channel, @@ -374,16 +403,17 @@ class DiscordMusicPlayer { } public parseYouTubeLink(query: string): YouTubeLink { - if (query.startsWith('https://www.youtube.com/watch?v=') || query.startsWith('http://www.youtube.com/watch?v=')) { + if ( + query.startsWith('https://www.youtube.com/watch?v=') || + query.startsWith('http://www.youtube.com/watch?v=') + ) { let data = this.parseURLQuery(query); - if (!data.v) - throw new Error('YouTube link is invalid'); + if (!data.v) throw new Error('YouTube link is invalid'); return { videoId: data.v, - list: (data.list ? (data.list !== "RDMM" ? data.list : undefined) : undefined) - } - } - else if (query.startsWith('https://youtu.be/') || query.startsWith('http://youtu.be/')) { + list: data.list ? (data.list !== 'RDMM' ? data.list : undefined) : undefined + }; + } else if (query.startsWith('https://youtu.be/') || query.startsWith('http://youtu.be/')) { //Get youtube video id after the url let videoId = query.split('/')[3]; @@ -392,16 +422,17 @@ class DiscordMusicPlayer { return { videoId: videoId - } - } - else if (query.startsWith('https://www.youtube.com/playlist?list=') || query.startsWith('http://www.youtube.com/playlist?list=')) { + }; + } else if ( + query.startsWith('https://www.youtube.com/playlist?list=') || + query.startsWith('http://www.youtube.com/playlist?list=') + ) { let listId = query.split('?list=')[1]; return { - videoId: "", + videoId: '', list: listId - } - } - else { + }; + } else { throw new Error('YouTube link is invalid'); } } @@ -418,8 +449,7 @@ class DiscordMusicPlayer { } return queryObject; } - } const DiscordMusicPlayer_Instance = new DiscordMusicPlayer(); -export default DiscordMusicPlayer_Instance; \ No newline at end of file +export default DiscordMusicPlayer_Instance; diff --git a/src/providers/Environment.ts b/src/providers/Environment.ts index ae0439c..19c9a6e 100644 --- a/src/providers/Environment.ts +++ b/src/providers/Environment.ts @@ -1,20 +1,13 @@ -import * as path from "path"; -import * as dotenv from "dotenv"; +import * as path from 'path'; +import * as dotenv from 'dotenv'; -import Logger from "../libs/Logger"; +import Logger from '../libs/Logger'; -const requiredENV = [ - 'NODE_ENV', - 'DATABASE_URL', - 'DISCORD_TOKEN', - 'PRIVATE_BOT', - 'OSU_API_KEY' -]; +const requiredENV = ['NODE_ENV', 'DATABASE_URL', 'DISCORD_TOKEN', 'PRIVATE_BOT', 'OSU_API_KEY']; class Environment { - public init(): void { - dotenv.config({ path: path.resolve(__dirname, "../../.env") }); + dotenv.config({ path: path.resolve(__dirname, '../../.env') }); for (let param of requiredENV) { if (this.isUndefinedOrEmpty(process.env[param])) @@ -22,7 +15,7 @@ class Environment { } // NODE_ENV Checks - if (this.get().NODE_ENV != "production" && this.get().NODE_ENV != "development") + if (this.get().NODE_ENV != 'production' && this.get().NODE_ENV != 'development') throw new Error('.env NODE_ENV must be either "production" or "development"'); // TODO: Discord token check @@ -31,7 +24,6 @@ class Environment { } public get(): any { - const NODE_ENV = process.env.NODE_ENV; const DISCORD_TOKEN = process.env.DISCORD_TOKEN; @@ -40,7 +32,7 @@ class Environment { const OSU_API_KEY = process.env.OSU_API_KEY; const YOUTUBE_COOKIE_BASE64 = process.env.YOUTUBE_COOKIE_BASE64; - + return { NODE_ENV, @@ -54,18 +46,14 @@ class Environment { } private isUndefinedOrEmpty(value: String | undefined): boolean { - if(typeof value === 'undefined') - return true; + if (typeof value === 'undefined') return true; - if(value === undefined) - return true; + if (value === undefined) return true; - if(value === '') - return true; + if (value === '') return true; return false; } - } export default new Environment(); diff --git a/src/providers/Prisma.ts b/src/providers/Prisma.ts index 5212871..5bb8739 100644 --- a/src/providers/Prisma.ts +++ b/src/providers/Prisma.ts @@ -1,11 +1,10 @@ import { PrismaClient } from '@prisma/client'; class Prisma { - public client: PrismaClient; - constructor () { - this.client = new PrismaClient; + constructor() { + this.client = new PrismaClient(); } public init(): void { @@ -15,7 +14,6 @@ class Prisma { public end(): void { this.client.$disconnect(); } - } -export default new Prisma(); \ No newline at end of file +export default new Prisma(); diff --git a/src/providers/osuAPI.ts b/src/providers/osuAPI.ts index ffdead4..65314c4 100644 --- a/src/providers/osuAPI.ts +++ b/src/providers/osuAPI.ts @@ -2,10 +2,9 @@ import { Api } from 'node-osu'; import Environment from './Environment'; class osuAPI { - public client: Api; - constructor () { + constructor() { this.client = new Api(Environment.get().OSU_API_KEY, { notFoundAsError: false, completeScores: true, @@ -21,9 +20,7 @@ class osuAPI { }); } - public end(): void { - } - + public end(): void {} } -export default new osuAPI(); \ No newline at end of file +export default new osuAPI(); diff --git a/src/services/Users.ts b/src/services/Users.ts index 0f43b84..fe1dddd 100644 --- a/src/services/Users.ts +++ b/src/services/Users.ts @@ -1,20 +1,17 @@ -import { User, Snowflake } from "discord.js"; -import Environment from "../providers/Environment"; +import { User, Snowflake } from 'discord.js'; +import Environment from '../providers/Environment'; class Users { public static isDeveloper(user: User | Snowflake) { - const developers: Snowflake[] = (Environment.get().DEVELOPER_IDS).split(','); + const developers: Snowflake[] = Environment.get().DEVELOPER_IDS.split(','); let userID; - if(user instanceof User) - userID = user.id; - else - userID = user; + if (user instanceof User) userID = user.id; + else userID = user; return developers.includes(userID); - } } -export default Users; \ No newline at end of file +export default Users; diff --git a/src/utils/DiscordInteraction.ts b/src/utils/DiscordInteraction.ts index 20d055b..61eaabb 100644 --- a/src/utils/DiscordInteraction.ts +++ b/src/utils/DiscordInteraction.ts @@ -1,180 +1,179 @@ -import Logger from "../libs/Logger"; -import DiscordProvider from "../providers/Discord"; -import { SlashCommandBuilder } from "@discordjs/builders"; +import { SlashCommandBuilder } from '@discordjs/builders'; + +import DiscordProvider from '../providers/Discord'; +import Logger from '../libs/Logger'; export const GLOBAL_COMMANDS: Object[] = []; - export const GUILD_COMMANDS: Object[] = []; -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('help') - .setDescription('Show help menu') +GUILD_COMMANDS.push(new SlashCommandBuilder().setName('help').setDescription('Show help menu')); +GUILD_COMMANDS.push( + new SlashCommandBuilder().setName('ping').setDescription('Measure network latency') ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('ping') - .setDescription('Measure network latency') +GUILD_COMMANDS.push( + new SlashCommandBuilder().setName('invite').setDescription('Invite me to your server!') ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('invite') - .setDescription('Invite me to your server!') +GUILD_COMMANDS.push( + new SlashCommandBuilder() + .setName('say') + .setDescription('Make me say something') + .addStringOption((option) => + option.setName('message').setDescription('Message you want me to say').setRequired(true) + ) ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('say') - .setDescription('Make me say something') - .addStringOption(option => option - .setName('message') - .setDescription('Message you want me to say') - .setRequired(true) - ) +GUILD_COMMANDS.push( + new SlashCommandBuilder() + .setName('interaction') + .setDescription('[Developer Only] Manage interaction') + .addSubcommand((info) => + info.setName('info').setDescription('[Developer Only] Interaction modules information') + ) + .addSubcommand((reloadAll) => + reloadAll + .setName('reloadall') + .setDescription('[Developer Only] Reload interaction for global and all guilds') + ) ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('interaction') - .setDescription('[Developer Only] Manage interaction') - .addSubcommand(info => info - .setName('info') - .setDescription('[Developer Only] Interaction modules information') - ) - .addSubcommand(reloadAll => reloadAll - .setName('reloadall') - .setDescription('[Developer Only] Reload interaction for global and all guilds') - ) +GUILD_COMMANDS.push( + new SlashCommandBuilder() + .setName('settings') + .setDescription('Change settings') + .addSubcommand((info) => + info + .setName('setprefix') + .setDescription('Change what prefix to use on this guild') + .addStringOption((prefix) => + prefix.setName('prefix').setDescription('New prefix to use').setRequired(true) + ) + ) + .addSubcommand((info) => + info + .setName('setenableserviceannouncement') + .setDescription('Enable or disable service announcement feature') + .addStringOption((prefix) => + prefix.setName('status').setDescription('New status').setRequired(true) + ) + ) + .addSubcommand((info) => + info + .setName('setserviceannouncementchannel') + .setDescription('Set channel where service announcement will be sent') + .addChannelOption((prefix) => + prefix.setName('channel').setDescription('New status').setRequired(true) + ) + ) ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('settings') - .setDescription('Change settings') - .addSubcommand(info => info - .setName('setprefix') - .setDescription('Change what prefix to use on this guild') - .addStringOption(prefix => prefix - .setName('prefix') - .setDescription('New prefix to use') - .setRequired(true) +GUILD_COMMANDS.push( + new SlashCommandBuilder() + .setName('membershipscreening') + .setDescription('Membership screening') + .addSubcommand((info) => + info.setName('info').setDescription('Show more information for membership screening') ) - ) - .addSubcommand(info => info - .setName('setenableserviceannouncement') - .setDescription('Enable or disable service announcement feature') - .addStringOption(prefix => prefix - .setName('status') - .setDescription('New status') - .setRequired(true) + .addSubcommand((enable) => + enable.setName('enable').setDescription('Enable membership screening') ) - ) - .addSubcommand(info => info - .setName('setserviceannouncementchannel') - .setDescription('Set channel where service announcement will be sent') - .addChannelOption(prefix => prefix - .setName('channel') - .setDescription('New status') - .setRequired(true) + .addSubcommand((enable) => + enable.setName('disable').setDescription('Disable membership screening') + ) + .addSubcommand((setrole) => + setrole + .setName('setrole') + .setDescription('Set a role that user will be granted when approved to join') + .addRoleOption((option) => + option + .setName('role') + .setDescription( + 'Select a role that user will be granted when approved to join' + ) + .setRequired(true) + ) + ) + .addSubcommand((setchannel) => + setchannel + .setName('setchannel') + .setDescription( + 'Set channel where membership screening approval request will be sent' + ) + .addChannelOption((option) => + option + .setName('channel') + .setDescription('Select a channel where approval request will be sent') + .setRequired(true) + ) + ) + .addSubcommand((createmessage) => + createmessage + .setName('createmessage') + .setDescription( + 'Create greeting message for membership screening into the channel. A message for new commers to read' + ) ) - ) ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('membershipscreening') - .setDescription('Membership screening') - .addSubcommand(info => info - .setName('info') - .setDescription('Show more information for membership screening') - ) - .addSubcommand(enable => enable - .setName('enable') - .setDescription('Enable membership screening') - ) - .addSubcommand(enable => enable - .setName('disable') - .setDescription('Disable membership screening') - ) - .addSubcommand(setrole => setrole - .setName('setrole') - .setDescription('Set a role that user will be granted when approved to join') - .addRoleOption(option => option - .setName('role') - .setDescription('Select a role that user will be granted when approved to join') - .setRequired(true) +GUILD_COMMANDS.push( + new SlashCommandBuilder() + .setName('osu') + .setDescription('Interact with the game osu!') + .addSubcommand((user) => + user + .setName('user') + .setDescription('Get user information on osu!') + .addStringOption((user) => + user.setName('user').setDescription('Username or User id').setRequired(true) + ) ) - ) - .addSubcommand(setchannel => setchannel - .setName('setchannel') - .setDescription('Set channel where membership screening approval request will be sent') - .addChannelOption(option => option - .setName('channel') - .setDescription('Select a channel where approval request will be sent') - .setRequired(true) + .addSubcommand((beatmap) => + beatmap + .setName('beatmap') + .setDescription('Get beatmap information on osu!') + .addStringOption((user) => + user.setName('beatmap').setDescription('Beatmap id').setRequired(true) + ) ) - ) - .addSubcommand(createmessage => createmessage - .setName('createmessage') - .setDescription('Create greeting message for membership screening into the channel. A message for new commers to read') - ) -); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('osu') - .setDescription('Interact with the game osu!') - .addSubcommand(user => user - .setName('user') - .setDescription('Get user information on osu!') - .addStringOption(user => user - .setName('user') - .setDescription('Username or User id') - .setRequired(true) - ) - ) - .addSubcommand(beatmap => beatmap - .setName('beatmap') - .setDescription('Get beatmap information on osu!') - .addStringOption(user => user - .setName('beatmap') - .setDescription('Beatmap id') - .setRequired(true) - ) - ) ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('userinfo') - .setDescription('Lookup discord user information') - .addSubcommand(user => user - .setName('user') +GUILD_COMMANDS.push( + new SlashCommandBuilder() + .setName('userinfo') .setDescription('Lookup discord user information') - .addUserOption(user => user - .setName('user') - .setDescription('Discord user to lookup') - .setRequired(true) + .addSubcommand((user) => + user + .setName('user') + .setDescription('Lookup discord user information') + .addUserOption((user) => + user.setName('user').setDescription('Discord user to lookup').setRequired(true) + ) ) - ) ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('stats') - .setDescription('Show the bot stats') +GUILD_COMMANDS.push( + new SlashCommandBuilder().setName('stats').setDescription('Show the bot stats') ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('skip') - .setDescription('Skip the current song') +GUILD_COMMANDS.push( + new SlashCommandBuilder().setName('skip').setDescription('Skip the current song') ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('nowplaying') - .setDescription('Show the current song information') +GUILD_COMMANDS.push( + new SlashCommandBuilder() + .setName('nowplaying') + .setDescription('Show the current song information') ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('join') - .setDescription('Join the voice channel') +GUILD_COMMANDS.push( + new SlashCommandBuilder().setName('join').setDescription('Join the voice channel') ); -GUILD_COMMANDS.push(new SlashCommandBuilder() - .setName('leave') - .setDescription('Leave the voice channel') +GUILD_COMMANDS.push( + new SlashCommandBuilder().setName('leave').setDescription('Leave the voice channel') ); - export const registerAllGlobalCommands = async () => { Logger.log('info', `Registering all global interaction commands`); - await DiscordProvider.client.application?.commands.set(JSON.parse(JSON.stringify(GLOBAL_COMMANDS))); -} + await DiscordProvider.client.application?.commands.set( + JSON.parse(JSON.stringify(GLOBAL_COMMANDS)) + ); +}; export const unregisterAllGlobalCommands = async () => { //const commands = await DiscordProvider.client.application?.commands.fetch(); @@ -187,32 +186,38 @@ export const unregisterAllGlobalCommands = async () => { /*for(const command of commands) { await DiscordProvider.client.application?.commands.delete(command[1]); }*/ - -} +}; export const registerAllGuildsCommands = async () => { - const guilds = DiscordProvider.client.guilds.cache.map(guild => guild.id); + const guilds = DiscordProvider.client.guilds.cache.map((guild) => guild.id); - for(const guild of guilds) { + for (const guild of guilds) { const guildObject = DiscordProvider.client.guilds.cache.get(guild); - if(!guildObject) continue; - - Logger.log('info', `Registering all interaction commands on guild ${guildObject.name} (${guildObject.id})`); - await DiscordProvider.client.guilds.cache.get(guildObject.id)?.commands.set(JSON.parse(JSON.stringify(GUILD_COMMANDS))); + if (!guildObject) continue; + + Logger.log( + 'info', + `Registering all interaction commands on guild ${guildObject.name} (${guildObject.id})` + ); + await DiscordProvider.client.guilds.cache + .get(guildObject.id) + ?.commands.set(JSON.parse(JSON.stringify(GUILD_COMMANDS))); } -} +}; export const unregisterAllGuildsCommands = async () => { - const guilds = DiscordProvider.client.guilds.cache.map(guild => guild.id); - - for(const guild of guilds) { + const guilds = DiscordProvider.client.guilds.cache.map((guild) => guild.id); + for (const guild of guilds) { const guildObject = DiscordProvider.client.guilds.cache.get(guild); - if(!guildObject) continue; + if (!guildObject) continue; - Logger.log('info', `Unregistering all interaction commands on guild ${guildObject.name} (${guildObject.id})`); + Logger.log( + 'info', + `Unregistering all interaction commands on guild ${guildObject.name} (${guildObject.id})` + ); await DiscordProvider.client.guilds.cache.get(guildObject.id)?.commands.set([]); //const commands = await guildObject.commands.fetch(); @@ -225,6 +230,5 @@ export const unregisterAllGuildsCommands = async () => { Logger.log('error', `Cannot unregister all interaction commands on guild ${guildObject.name} (${guildObject.id})`); } }*/ - } -} \ No newline at end of file +}; diff --git a/src/utils/DiscordMessage.ts b/src/utils/DiscordMessage.ts index 8b58e13..cbd6eda 100644 --- a/src/utils/DiscordMessage.ts +++ b/src/utils/DiscordMessage.ts @@ -1,186 +1,274 @@ -import { MessageEmbed, User, MessagePayload, MessageOptions, GuildTextBasedChannel, TextChannel, DMChannel, PartialDMChannel, BaseGuildTextChannel, Message, ColorResolvable, Interaction, InteractionReplyOptions, CommandInteraction } from "discord.js"; -import App from ".."; -import Logger from "../libs/Logger"; -import { HybridInteractionMessage } from "./DiscordModule"; +import { + MessageEmbed, + User, + MessagePayload, + MessageOptions, + GuildTextBasedChannel, + TextChannel, + DMChannel, + PartialDMChannel, + BaseGuildTextChannel, + Message, + ColorResolvable, + Interaction, + InteractionReplyOptions, + CommandInteraction +} from 'discord.js'; + +import App from '..'; +import { HybridInteractionMessage } from './DiscordModule'; +import Logger from '../libs/Logger'; const emotes = { - "yumiloading": "" + yumiloading: '' }; -export function makeEmbed(icon: string | undefined, title: string, description: any, color: ColorResolvable, fields: any, user: User, setTimestamp: boolean) { - +export function makeEmbed( + icon: string | undefined, + title: string, + description: any, + color: ColorResolvable, + fields: any, + user: User, + setTimestamp: boolean +) { const embed = new MessageEmbed(); embed.setColor(color || '#FFFFFF'); - if(typeof icon === 'undefined') - embed.setTitle(title); - else - embed.setTitle(`${icon} ${title}`); + if (typeof icon === 'undefined') embed.setTitle(title); + else embed.setTitle(`${icon} ${title}`); - if (typeof description !== 'undefined') - embed.setDescription(description) + if (typeof description !== 'undefined') embed.setDescription(description); - if(setTimestamp) - embed.setTimestamp(); + if (setTimestamp) embed.setTimestamp(); - if(typeof user !== 'undefined') + if (typeof user !== 'undefined') embed.footer = { text: `${user.username} | v${App.version}`, iconURL: `${user.displayAvatarURL()}?size=4096` - } + }; else embed.footer = { text: `v${App.version}` - } - - if (typeof fields !== 'undefined') - embed.addFields(fields); - - return embed; + }; + if (typeof fields !== 'undefined') embed.addFields(fields); + + return embed; } export function makeSuccessEmbed(options: any) { - return makeEmbed(typeof options.icon === 'undefined' ? "โœ…" : options.icon, options.title, options.description, '#B5EAD7', options.fields, options.user, options.setTimestamp || true); + return makeEmbed( + typeof options.icon === 'undefined' ? 'โœ…' : options.icon, + options.title, + options.description, + '#B5EAD7', + options.fields, + options.user, + options.setTimestamp || true + ); } export function makeWarningEmbed(options: any) { - return makeEmbed(typeof options.icon === 'undefined' ? "โš ๏ธ" : options.icon, options.title, options.description, '#FFEEAD', options.fields, options.user, options.setTimestamp || true); + return makeEmbed( + typeof options.icon === 'undefined' ? 'โš ๏ธ' : options.icon, + options.title, + options.description, + '#FFEEAD', + options.fields, + options.user, + options.setTimestamp || true + ); } export function makeErrorEmbed(options: any) { - return makeEmbed(typeof options.icon === 'undefined' ? "โŒ" : options.icon, options.title, options.description, '#FF9AA2', options.fields, options.user, options.setTimestamp || true); + return makeEmbed( + typeof options.icon === 'undefined' ? 'โŒ' : options.icon, + options.title, + options.description, + '#FF9AA2', + options.fields, + options.user, + options.setTimestamp || true + ); } export function makeProcessingEmbed(options: any) { - return makeEmbed(typeof options.icon === 'undefined' ? getEmotes().yumiloading : options.icon, options.title, options.description, '#E2F0CB', options.fields, options.user, options.setTimestamp || true); + return makeEmbed( + typeof options.icon === 'undefined' ? getEmotes().yumiloading : options.icon, + options.title, + options.description, + '#E2F0CB', + options.fields, + options.user, + options.setTimestamp || true + ); } export function makeInfoEmbed(options: any) { - return makeEmbed(typeof options.icon === 'undefined' ? "๐Ÿ”ฎ" : options.icon, options.title, options.description, '#C7CEEA', options.fields, options.user, options.setTimestamp || true); + return makeEmbed( + typeof options.icon === 'undefined' ? '๐Ÿ”ฎ' : options.icon, + options.title, + options.description, + '#C7CEEA', + options.fields, + options.user, + options.setTimestamp || true + ); } -export async function sendMessage(channel: TextChannel | DMChannel | BaseGuildTextChannel | GuildTextBasedChannel | PartialDMChannel , user: User | undefined, options: string | MessagePayload | MessageOptions) { - +export async function sendMessage( + channel: + | TextChannel + | DMChannel + | BaseGuildTextChannel + | GuildTextBasedChannel + | PartialDMChannel, + user: User | undefined, + options: string | MessagePayload | MessageOptions +) { let message; - try { message = await channel.send(options); } - catch(error) { - if(typeof user === 'undefined') { - return Logger.error(`Cannot find available destinations to send the message CID: ${channel.id} C_ERR: ${error}`); + try { + message = await channel.send(options); + } catch (error) { + if (typeof user === 'undefined') { + return Logger.error( + `Cannot find available destinations to send the message CID: ${channel.id} C_ERR: ${error}` + ); } - try { message = await user.send(options); } - catch(errorDM) { - Logger.error(`Cannot find available destinations to send the message CID: ${channel.id} UID: ${user.id} C_ERR: ${error} DM_ERR: ${errorDM}`); + try { + message = await user.send(options); + } catch (errorDM) { + Logger.error( + `Cannot find available destinations to send the message CID: ${channel.id} UID: ${user.id} C_ERR: ${error} DM_ERR: ${errorDM}` + ); return; } } finally { return message; } - } -export async function sendReply(rMessage: Message, options: string | MessagePayload | MessageOptions) { - +export async function sendReply( + rMessage: Message, + options: string | MessagePayload | MessageOptions +) { let message; - try { message = await rMessage.reply(options); } - catch(error) { - try { message = await rMessage.author.send(options); } - catch(errorDM) { - Logger.error(`Cannot find available destinations to reply the message to. MID: ${rMessage.id} CID: ${rMessage.channel.id} UID: ${rMessage.author.id} C_ERR: ${error} DM_ERR: ${errorDM}`); + try { + message = await rMessage.reply(options); + } catch (error) { + try { + message = await rMessage.author.send(options); + } catch (errorDM) { + Logger.error( + `Cannot find available destinations to reply the message to. MID: ${rMessage.id} CID: ${rMessage.channel.id} UID: ${rMessage.author.id} C_ERR: ${error} DM_ERR: ${errorDM}` + ); return; } } finally { return message; } - } - -export async function sendMessageOrInteractionResponse(data: Message | Interaction, payload: MessageOptions | InteractionReplyOptions, replace = false) { +export async function sendMessageOrInteractionResponse( + data: Message | Interaction, + payload: MessageOptions | InteractionReplyOptions, + replace = false +) { const isSlashCommand = data instanceof CommandInteraction && data.isCommand(); const isMessage = data instanceof Message; - if(isSlashCommand || (data instanceof Interaction && ( data.isSelectMenu() || data.isButton()))) { - if(!data.replied) { + if ( + isSlashCommand || + (data instanceof Interaction && (data.isSelectMenu() || data.isButton())) + ) { + if (!data.replied) { let message; try { - if(!data.deferred) - return await data.reply(payload as InteractionReplyOptions); - else - return await data.editReply(payload); - } - catch(errorDM) { - Logger.error(`Cannot find available destinations to send the message CID: ${data.channel!.id} UID: ${data.user.id} DM_ERR: ${errorDM}`); + if (!data.deferred) return await data.reply(payload as InteractionReplyOptions); + else return await data.editReply(payload); + } catch (errorDM) { + Logger.error( + `Cannot find available destinations to send the message CID: ${ + data.channel!.id + } UID: ${data.user.id} DM_ERR: ${errorDM}` + ); return; } finally { return message; } - } - else { + } else { let message; - try { - if(replace) - return await data.editReply(payload); - else - return await data.followUp(payload as InteractionReplyOptions); - } - catch(errorDM) { - Logger.error(`Cannot find available destinations to send the message CID: ${data.channel!.id} UID: ${data.user.id} DM_ERR: ${errorDM}`); + try { + if (replace) return await data.editReply(payload); + else return await data.followUp(payload as InteractionReplyOptions); + } catch (errorDM) { + Logger.error( + `Cannot find available destinations to send the message CID: ${ + data.channel!.id + } UID: ${data.user.id} DM_ERR: ${errorDM}` + ); return; } finally { return message; } } - } - else if(isMessage) return await sendReply(data, payload as MessageOptions); + } else if (isMessage) return await sendReply(data, payload as MessageOptions); } -export async function sendHybridInteractionMessageResponse(data: HybridInteractionMessage, payload: MessageOptions | InteractionReplyOptions, replace = false): (Promise) { - - if(data.isSlashCommand() || data.isButton() || data.isSelectMenu()) { - +export async function sendHybridInteractionMessageResponse( + data: HybridInteractionMessage, + payload: MessageOptions | InteractionReplyOptions, + replace = false +): Promise { + if (data.isSlashCommand() || data.isButton() || data.isSelectMenu()) { const messageComponent = data.getMessageComponentInteraction(); - if(!messageComponent.replied) { + if (!messageComponent.replied) { let message; try { - if(!messageComponent.deferred) { + if (!messageComponent.deferred) { await messageComponent.reply(payload as InteractionReplyOptions); return messageComponent; - } - else { + } else { await messageComponent.editReply(payload); return messageComponent; } - } - catch(errorDM) { - Logger.error(`Cannot find available destinations to send the message CID: ${messageComponent.channel!.id} UID: ${messageComponent.user.id} DM_ERR: ${errorDM}`); + } catch (errorDM) { + Logger.error( + `Cannot find available destinations to send the message CID: ${ + messageComponent.channel!.id + } UID: ${messageComponent.user.id} DM_ERR: ${errorDM}` + ); return; } finally { return message; } - } - else { + } else { let message; - try { - if(replace) - return (await messageComponent.editReply(payload) as Message); + try { + if (replace) return (await messageComponent.editReply(payload)) as Message; else - return (await messageComponent.followUp(payload as InteractionReplyOptions) as Message); - } - catch(errorDM) { - Logger.error(`Cannot find available destinations to send the message CID: ${messageComponent.channel!.id} UID: ${messageComponent.user.id} DM_ERR: ${errorDM}`); + return (await messageComponent.followUp( + payload as InteractionReplyOptions + )) as Message; + } catch (errorDM) { + Logger.error( + `Cannot find available destinations to send the message CID: ${ + messageComponent.channel!.id + } UID: ${messageComponent.user.id} DM_ERR: ${errorDM}` + ); return; } finally { return message; } } - } - else if(data.isMessage()) return await sendReply(data.getMessage(), payload as MessageOptions); + } else if (data.isMessage()) + return await sendReply(data.getMessage(), payload as MessageOptions); } export function getEmotes() { return emotes; -} \ No newline at end of file +} diff --git a/src/utils/DiscordModule.ts b/src/utils/DiscordModule.ts index df0131d..a2293fe 100644 --- a/src/utils/DiscordModule.ts +++ b/src/utils/DiscordModule.ts @@ -1,45 +1,63 @@ -import { Guild, Interaction, Message, GuildMember, CommandInteraction, ButtonInteraction, TextBasedChannel, MessageComponentInteraction, User, SelectMenuInteraction } from "discord.js"; +import { + Guild, + Interaction, + Message, + GuildMember, + CommandInteraction, + ButtonInteraction, + TextBasedChannel, + MessageComponentInteraction, + User, + SelectMenuInteraction +} from 'discord.js'; export default class DiscordModule { - public id?: string; - public commands?: (string[] | null) = null; - public commandInteractionName?: (string | null) = null; + public commands?: string[] | null = null; + public commandInteractionName?: string | null = null; - constructor({ id, command, commandInteractionName }: { - id?: string, - command?: (string[] | null), - commandInteractionName?: (string | null) + constructor({ + id, + command, + commandInteractionName + }: { + id?: string; + command?: string[] | null; + commandInteractionName?: string | null; } = {}) { - this.id = id; - this.commands = command; - this.commandInteractionName = commandInteractionName; + this.id = id; + this.commands = command; + this.commandInteractionName = commandInteractionName; } - Init(): (void | Promise) {} - Ready(): (void | Promise) {} + Init(): void | Promise {} + Ready(): void | Promise {} - GuildOnCommand(command: string, args: any, message: Message): (void | Promise) {} - GuildOnModuleCommand(args: any, message: Message): (void | Promise) {} + GuildOnCommand(command: string, args: any, message: Message): void | Promise {} + GuildOnModuleCommand(args: any, message: Message): void | Promise {} - GuildInteractionCreate(interaction: Interaction): (void | Promise) {} - GuildModuleInteractionCreate(interaction: Interaction): (void | Promise) {} + GuildInteractionCreate(interaction: Interaction): void | Promise {} + GuildModuleInteractionCreate(interaction: Interaction): void | Promise {} - GuildCommandInteractionCreate(interaction: CommandInteraction): (void | Promise) {} - GuildModuleCommandInteractionCreate(interaction: CommandInteraction): (void | Promise) {} + GuildCommandInteractionCreate(interaction: CommandInteraction): void | Promise {} + GuildModuleCommandInteractionCreate( + interaction: CommandInteraction + ): void | Promise {} - GuildSelectMenuInteractionCreate(interaction: SelectMenuInteraction): (void | Promise) {} + GuildSelectMenuInteractionCreate( + interaction: SelectMenuInteraction + ): void | Promise {} - GuildButtonInteractionCreate(interaction: ButtonInteraction): (void | Promise) {} + GuildButtonInteractionCreate(interaction: ButtonInteraction): void | Promise {} - GuildCreate(guild: Guild): (void | Promise) {} - GuildMemberAdd(member: GuildMember): (void | Promise) {} - GuildMessageCreate(message: Message): (void | Promise) {} + GuildCreate(guild: Guild): void | Promise {} + GuildMemberAdd(member: GuildMember): void | Promise {} + GuildMessageCreate(message: Message): void | Promise {} } export class HybridInteractionMessage { public data: Interaction | Message; - constructor (data: Interaction | Message) { + constructor(data: Interaction | Message) { this.data = data; } @@ -54,7 +72,7 @@ export class HybridInteractionMessage { public isButton(): boolean { return this.data instanceof ButtonInteraction && this.data.isButton(); } - + public isSelectMenu(): boolean { return this.data instanceof SelectMenuInteraction && this.data.isSelectMenu(); } @@ -63,58 +81,56 @@ export class HybridInteractionMessage { return this.data instanceof Message; } - public getChannel(): (TextBasedChannel | null) { + public getChannel(): TextBasedChannel | null { return this.data.channel; } - public getGuild(): (Guild | null) { + public getGuild(): Guild | null { return this.data.guild; } - public getUser(): (User | null) { - return (this.isInteraction()) ? this.getInteraction().user : this.getMessage().author + public getUser(): User | null { + return this.isInteraction() ? this.getInteraction().user : this.getMessage().author; } - public getMember(): (GuildMember | null) { - return (this.data.member as GuildMember); + public getMember(): GuildMember | null { + return this.data.member as GuildMember; } public getInteraction(): Interaction { - if(this.isMessage()) - throw new Error("Unable to cast interaction to message"); + if (this.isMessage()) throw new Error('Unable to cast interaction to message'); return this.data as Interaction; } public getSlashCommand(): CommandInteraction { - if(this.isInteraction() && !(this.data as CommandInteraction)) - throw new Error("Unable to cast to MessageComponentInteraction"); + if (this.isInteraction() && !(this.data as CommandInteraction)) + throw new Error('Unable to cast to MessageComponentInteraction'); return this.data as CommandInteraction; } public getSelectMenu(): SelectMenuInteraction { - if(this.isInteraction() && !(this.data as SelectMenuInteraction)) - throw new Error("Unable to cast to SelectMenuInteraction"); + if (this.isInteraction() && !(this.data as SelectMenuInteraction)) + throw new Error('Unable to cast to SelectMenuInteraction'); return this.data as SelectMenuInteraction; } public getMessageComponentInteraction(): MessageComponentInteraction { - if(this.isInteraction() && !(this.data as MessageComponentInteraction)) - throw new Error("Unable to cast to MessageComponentInteraction"); + if (this.isInteraction() && !(this.data as MessageComponentInteraction)) + throw new Error('Unable to cast to MessageComponentInteraction'); return this.data as MessageComponentInteraction; } public getMessage(): Message { - if(this.isInteraction()) - throw new Error("Unable to cast message to interaction"); + if (this.isInteraction()) throw new Error('Unable to cast message to interaction'); return this.data as Message; } - public getRaw(): (Interaction | Message) { + public getRaw(): Interaction | Message { return this.data; } -} \ No newline at end of file +}