Formatted code and clean up

This commit is contained in:
2022-06-06 14:59:53 +07:00
parent 8b066dde58
commit 573040362d
29 changed files with 2208 additions and 1556 deletions
+14 -16
View File
@@ -1,19 +1,18 @@
import DiscordModule from "../utils/DiscordModule"; import { Guild } from 'discord.js';
import { Guild } from "discord.js"; import DiscordModule from '../utils/DiscordModule';
import Logger from "../libs/Logger"; import DiscordProvider from '../providers/Discord';
import Cache from "../providers/Cache";
import DiscordProvider from "../providers/Discord"; import Logger from '../libs/Logger';
import Prisma from "../providers/Prisma"; import Cache from '../providers/Cache';
import Prisma from '../providers/Prisma';
export default class Core extends DiscordModule { export default class Core extends DiscordModule {
public id: string = 'Discord_Core';
public id: string = "Discord_Core";
async Ready() { async Ready() {
let data = []; 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 }); data.push({ id: Guild.id });
} }
@@ -25,20 +24,19 @@ export default class Core extends DiscordModule {
await Cache.updateGuildsCache(); await Cache.updateGuildsCache();
setInterval(() => { setInterval(() => {
Cache.updateGuildsCache(); Cache.updateGuildsCache();
}, 5 * 60 * 1000) }, 5 * 60 * 1000);
setInterval(() => { setInterval(() => {
DiscordProvider.client.user!.setActivity("for your heart 💖", { DiscordProvider.client.user!.setActivity('for your heart 💖', {
type: "COMPETING" type: 'COMPETING'
}); });
}, 5 * 60 * 1000) }, 5 * 60 * 1000);
Logger.info('Core started successfully'); Logger.info('Core started successfully');
} }
async GuildCreate(guild: Guild) { 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({ await Prisma.client.guild.create({
data: { data: {
+24 -19
View File
@@ -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 DiscordProvider from '../providers/Discord';
import { sendHybridInteractionMessageResponse, makeInfoEmbed } from "../utils/DiscordMessage"; 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 = { const EMBEDS = {
INFO: async (data: Message | Interaction) => { INFO: async (data: Message | Interaction) => {
let GuildCache = await Cache.getGuild(data.guildId!); let GuildCache = await Cache.getGuild(data.guildId!);
// TODO: Better error handling // TODO: Better error handling
if(typeof GuildCache === 'undefined') if (typeof GuildCache === 'undefined') throw new Error('Guild not found');
throw new Error("Guild not found");
let prefix = GuildCache.prefix || '>'; let prefix = GuildCache.prefix || '>';
let _e = makeInfoEmbed({ let _e = makeInfoEmbed({
icon: "💌", icon: '💌',
title: `Help - ${DiscordProvider.client.user?.username}`, 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: [ fields: [
{ {
name: '☕ General', name: '☕ General',
@@ -52,18 +56,17 @@ const EMBEDS = {
inline: false 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`); _e.setThumbnail(`${DiscordProvider.client.user?.displayAvatarURL()}?size=4096`);
return _e; return _e;
} }
} };
export default class Help extends DiscordModule { export default class Help extends DiscordModule {
public id = 'Discord_Help';
public id = "Discord_Help"; public commands = ['help'];
public commands = ["help"]; public commandInteractionName = 'help';
public commandInteractionName = "help";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -74,9 +77,11 @@ export default class Help extends DiscordModule {
} }
async run(data: HybridInteractionMessage, args: any) { 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()) if (message && data.isMessage())
return new HybridInteractionMessage(message).getMessage().react("♥"); return new HybridInteractionMessage(message).getMessage().react('♥');
} }
} }
+71 -48
View File
@@ -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 Users from '../services/Users';
import { makeInfoEmbed, makeErrorEmbed, makeSuccessEmbed, makeProcessingEmbed, sendHybridInteractionMessageResponse } from "../utils/DiscordMessage";
import {registerAllGuildsCommands, unregisterAllGuildsCommands} from "../utils/DiscordInteraction"; import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule';
import Users from "../services/Users"; import {
makeInfoEmbed,
makeErrorEmbed,
makeSuccessEmbed,
makeProcessingEmbed,
sendHybridInteractionMessageResponse
} from '../utils/DiscordMessage';
import {
registerAllGuildsCommands,
unregisterAllGuildsCommands
} from '../utils/DiscordInteraction';
const EMBEDS = { const EMBEDS = {
INTERACTION_INFO: (data: Message | Interaction) => { INTERACTION_INFO: (data: Message | Interaction) => {
@@ -16,43 +26,42 @@ const EMBEDS = {
value: '``reloadAll``' value: '``reloadAll``'
} }
], ],
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
}, },
PROCESSING: (data: Message | Interaction) => { PROCESSING: (data: Message | Interaction) => {
return makeProcessingEmbed({ return makeProcessingEmbed({
icon: (data instanceof Message) ? undefined : '⌛', icon: data instanceof Message ? undefined : '⌛',
title: `Performing actions`, title: `Performing actions`,
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
}, },
NOT_DEVELOPER: (data: Message | Interaction) => { NOT_DEVELOPER: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Developer only', title: 'Developer only',
description: `This command is restricted to the developers 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) => { RELOADALL_SUCCESS: (data: Message | Interaction) => {
return makeSuccessEmbed({ return makeSuccessEmbed({
title: 'Reloaded all Interaction', 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) => { RELOADALL_ERROR: (data: Message | Interaction, err: any) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'An error occurred while trying to reload interaction', title: 'An error occurred while trying to reload interaction',
description: '```' + err + '```', description: '```' + err + '```',
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}) });
} }
} };
export default class InteractionManager extends DiscordModule { export default class InteractionManager extends DiscordModule {
public id = 'Discord_InteractionManager';
public id = "Discord_InteractionManager"; public commands = ['interaction'];
public commands = ["interaction"]; public commandInteractionName = 'interaction';
public commandInteractionName = "interaction";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -63,58 +72,72 @@ export default class InteractionManager extends DiscordModule {
} }
async run(data: HybridInteractionMessage, args: any) { async run(data: HybridInteractionMessage, args: any) {
const user = data.getUser(); const user = data.getUser();
if(!user) return; if (!user) return;
if(!Users.isDeveloper(user.id)) 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 = { 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())]
let _placeholder = await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PROCESSING(data.getRaw())] }); });
if (_placeholder) if (_placeholder) placeholder = new HybridInteractionMessage(_placeholder);
placeholder = new HybridInteractionMessage(_placeholder);
try { try {
await unregisterAllGuildsCommands(); await unregisterAllGuildsCommands();
await registerAllGuildsCommands(); await registerAllGuildsCommands();
if(data && data.isMessage() && placeholder && placeholder.isMessage()) if (data && data.isMessage() && placeholder && placeholder.isMessage())
return placeholder.getMessage().edit({ embeds: [EMBEDS.RELOADALL_SUCCESS(data.getRaw())] }); return placeholder
else if(data.isSlashCommand()) .getMessage()
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.RELOADALL_SUCCESS(data.getRaw())]}, true); .edit({ embeds: [EMBEDS.RELOADALL_SUCCESS(data.getRaw())] });
else if (data.isSlashCommand())
return await sendHybridInteractionMessageResponse(
data,
{ embeds: [EMBEDS.RELOADALL_SUCCESS(data.getRaw())] },
true
);
} catch (err) { } catch (err) {
if(data && data.isMessage() && placeholder && placeholder.isMessage()) if (data && data.isMessage() && placeholder && placeholder.isMessage())
return placeholder.getMessage().edit({ embeds: [EMBEDS.RELOADALL_ERROR(data.getRaw(), err)] }); return placeholder
else if(data.isSlashCommand()) .getMessage()
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.RELOADALL_ERROR(data.getRaw(), err)] }, true); .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; let query;
if(data.isMessage()) { if (data.isMessage()) {
if(args.length === 0) if (args.length === 0)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INTERACTION_INFO(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.INTERACTION_INFO(data.getRaw())]
});
query = args[0].toLowerCase(); query = args[0].toLowerCase();
} } else if (data.isSlashCommand()) {
else if(data.isSlashCommand()) {
query = args.getSubcommand(); query = args.getSubcommand();
} }
switch(query) { switch (query) {
case "info": case 'info':
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INTERACTION_INFO(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
case "reloadall": embeds: [EMBEDS.INTERACTION_INFO(data.getRaw())]
});
case 'reloadall':
return await funct.reloadAll(data); return await funct.reloadAll(data);
} }
} }
} }
+19 -15
View File
@@ -1,30 +1,32 @@
import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; import { Message, CommandInteraction, Interaction } from 'discord.js';
import { Message, CommandInteraction, Interaction } from "discord.js"; import Environment from '../providers/Environment';
import { sendHybridInteractionMessageResponse, makeInfoEmbed } from "../utils/DiscordMessage"; import DiscordProvider from '../providers/Discord';
import DiscordProvider from "../providers/Discord"; import Users from '../services/Users';
import Users from "../services/Users"
import Environment from "../providers/Environment"; import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule';
import { sendHybridInteractionMessageResponse, makeInfoEmbed } from '../utils/DiscordMessage';
const EMBEDS = { const EMBEDS = {
INVITE_INFO: (data: Message | Interaction) => { INVITE_INFO: (data: Message | Interaction) => {
let message; 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)`; 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({ return makeInfoEmbed({
title: `Invite`, title: `Invite`,
description: message || `${DiscordProvider.client.user?.username}'s invite is currently private. Only the developers can add me to another server`, description:
user: (data instanceof Interaction) ? data.user : data.author 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 { export default class Invite extends DiscordModule {
public id: string = 'Discord_Invite';
public id: string = "Discord_Invite"; public commands = ['invite'];
public commands = ["invite"]; public commandInteractionName = 'invite';
public commandInteractionName = "invite";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -35,6 +37,8 @@ export default class Invite extends DiscordModule {
} }
async run(data: HybridInteractionMessage, args: any) { 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())]
});
} }
} }
+261 -149
View File
@@ -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 DiscordProvider from '../providers/Discord';
import App from ".."; import Prisma from '../providers/Prisma';
import { makeSuccessEmbed, makeInfoEmbed, makeErrorEmbed, sendHybridInteractionMessageResponse, sendMessage } from "../utils/DiscordMessage";
import DiscordProvider from "../providers/Discord"; import {
import Prisma from "../providers/Prisma"; makeSuccessEmbed,
makeInfoEmbed,
makeErrorEmbed,
sendHybridInteractionMessageResponse,
sendMessage
} from '../utils/DiscordMessage';
import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule';
const EMBEDS = { const EMBEDS = {
NO_PERMISSION: (data: Message | Interaction) => { NO_PERMISSION: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'You need ``ADMINISTRATOR`` permission on this guild!', 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) => { NO_PARAMETER: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Missing parameter', title: 'Missing parameter',
description: `You must define membership screening channel and role to enable this feature`, 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) => { NO_ROLE_MENTIONED: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'No role mentioned', 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) => { NO_ROLE_FOUND: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Cannot find that role', 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) => { NO_CHANNEL_MENTIONED: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'No channel mentioned', 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) => { NO_CHANNEL_FOUND: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Cannot find that channel', 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) => { MSINFO: (data: Message | Interaction) => {
@@ -54,106 +74,120 @@ const EMBEDS = {
value: '``setRole`` ``setChannel`` ``createMessage``' 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) => { ALREADY_ENABLED: (data: Message | Interaction) => {
return makeInfoEmbed({ return makeInfoEmbed({
title: 'Membership Screening is already enabled', 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) => { MESSAGE_CREATED: (data: Message | Interaction) => {
return makeSuccessEmbed({ return makeSuccessEmbed({
title: 'Membership Screening message created', 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) => { ALREADY_DISABLED: (data: Message | Interaction) => {
return makeInfoEmbed({ return makeInfoEmbed({
title: 'Membership Screening is already disabled', 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) => { ENABLED: (data: Message | Interaction) => {
return makeSuccessEmbed({ return makeSuccessEmbed({
title: 'Enabled Membership Screening', title: 'Enabled Membership Screening',
description: `All new member join request will be sent in your defined channel`, 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) => { DISABLED: (data: Message | Interaction) => {
return makeSuccessEmbed({ return makeSuccessEmbed({
title: 'Disabled Membership Screening', title: 'Disabled Membership Screening',
description: `No longer accepting request, all new member can join directly`, 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) => { MANAGED_ROLE: (data: Message | Interaction, role: Role) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'You cannot use this role', title: 'You cannot use this role',
description: '``' + role.name + '``' + ' is managed by external service and cannot be used', description:
user: (data instanceof Interaction) ? data.user : data.author '``' + 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) => { CONFIGURED_ROLE: (data: Message | Interaction, role: Role) => {
return makeSuccessEmbed({ return makeSuccessEmbed({
title: 'Configured Membership Screening Role', title: 'Configured Membership Screening Role',
description: 'New member will be given a ' + '``' + role.name + '``' + ' role after approval', description:
user: (data instanceof Interaction) ? data.user : data.author '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) => { CONFIGURED_CHANNEL: (data: Message | Interaction, channel: GuildChannel) => {
return makeSuccessEmbed({ return makeSuccessEmbed({
title: 'Configured Membership Screening Channel', title: 'Configured Membership Screening Channel',
description: 'Anyone with ``VIEW_CHANNEL`` permission in ' + '``' + channel.name + '``' + ' can approve or deny request', description:
user: (data instanceof Interaction) ? data.user : data.author '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) => { INVALID_CHANNEL: (data: Message | Interaction, channel: GuildChannel) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Invalid channel type, only TextChannel is supported', title: 'Invalid channel type, only TextChannel is supported',
description: '``' + channel.name + '``' + ' is not a text channel', 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({ return makeErrorEmbed({
title: 'Thread channel is not supported', title: 'Thread channel is not supported',
description: '``' + channel.name + '``' + ' is a thread channel. Please use a regular text channel', description:
user: (data instanceof Interaction) ? data.user : data.author '``' +
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) => { BOT_NO_PERMISSION: (data: Message | Interaction, channel: GuildChannel) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: `I don't have permission`, title: `I don't have permission`,
description: 'I cannot access/send message in ' + '``' + channel.name + '``', 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) => { NO_LONGER_VALID_ROLE: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'The configured role is no longer valid. Please update the role in configuration', 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) => { CANNOT_PERFORM_ASSIGN_ROLE: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Cannot grant the role to user, make sure I have permission to do that', 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) => { CANNOT_PERFORM_ASSIGN_KICK: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Cannot kick the user, make sure I have permission to do that', 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) => { CANNOT_PERFORM_ASSIGN_BAN: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Cannot ban the user, make sure I have permission to do that', 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: () => { CREATE_MESSAGE: () => {
return makeInfoEmbed({ return makeInfoEmbed({
@@ -161,15 +195,14 @@ const EMBEDS = {
title: 'Welcome to this server!', 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)`, 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 user: DiscordProvider.client.user
}) });
} }
} };
export default class MembershipScreening extends DiscordModule { export default class MembershipScreening extends DiscordModule {
public id = 'Discord_MembershipScreening';
public id = "Discord_MembershipScreening"; public commands = ['membershipscreening', 'ms'];
public commands = ["membershipscreening", "ms"]; public commandInteractionName = 'membershipscreening';
public commandInteractionName = "membershipscreening";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -180,20 +213,22 @@ export default class MembershipScreening extends DiscordModule {
} }
async GuildButtonInteractionCreate(interaction: ButtonInteraction) { async GuildButtonInteractionCreate(interaction: ButtonInteraction) {
const hybridData = new HybridInteractionMessage(interaction); const hybridData = new HybridInteractionMessage(interaction);
const guild = hybridData.getGuild(); const guild = hybridData.getGuild();
const user = hybridData.getUser(); const user = hybridData.getUser();
const channel = hybridData.getChannel(); const channel = hybridData.getChannel();
if(!guild || !user || !channel) return; if (!guild || !user || !channel) return;
if (!this.isJsonValid(interaction.customId)) return; if (!this.isJsonValid(interaction.customId)) return;
const payload = JSON.parse(interaction.customId); const payload = JSON.parse(interaction.customId);
if (typeof payload.m === 'undefined' || if (
typeof payload.m === 'undefined' ||
typeof payload.a === 'undefined' || typeof payload.a === 'undefined' ||
payload.m !== 'MembershipScreening') return; payload.m !== 'MembershipScreening'
)
return;
const message = await channel.messages.fetch(interaction.message.id); const message = await channel.messages.fetch(interaction.message.id);
if (!message) return; if (!message) return;
@@ -204,75 +239,96 @@ export default class MembershipScreening extends DiscordModule {
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; if (!PrismaGuild) return;
if (!PrismaGuild.MembershipScreening_Enabled || if (
!PrismaGuild.MembershipScreening_Enabled ||
PrismaGuild.MembershipScreening_ApprovalChannel === null || PrismaGuild.MembershipScreening_ApprovalChannel === null ||
PrismaGuild.MembershipScreening_GivenRole === null) return; PrismaGuild.MembershipScreening_GivenRole === null
)
return;
embed[0].footer = { embed[0].footer = {
text: `${interaction.user.username} | v${App.version}`, text: `${interaction.user.username} | v${App.version}`,
iconURL: `${interaction.user.displayAvatarURL()}?size=4096` iconURL: `${interaction.user.displayAvatarURL()}?size=4096`
} };
if (['approve', 'deny', 'ban'].includes(payload.a)) { if (['approve', 'deny', 'ban'].includes(payload.a)) {
if (!payload.d.requester) return; if (!payload.d.requester) return;
const role = (await guild.roles.fetch()).find(role => role.id === PrismaGuild.MembershipScreening_GivenRole); const role = (await guild.roles.fetch()).find(
const requesterMember = (await guild.members.fetch()).find(member => member.id === payload.d.requester); (role) => role.id === PrismaGuild.MembershipScreening_GivenRole
);
const requesterMember = (await guild.members.fetch()).find(
(member) => member.id === payload.d.requester
);
if (!role) 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) { 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 }); return await message.edit({ components: [], embeds: embed });
} }
if (requesterMember.roles.cache.has(PrismaGuild.MembershipScreening_GivenRole)) { 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 }); return await message.edit({ components: [], embeds: embed });
} }
if (payload.a === 'approve') { if (payload.a === 'approve') {
try { try {
await requesterMember.roles.add(role); 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 }); await message.edit({ components: [], embeds: embed });
} catch (err) {
return interaction.reply({
ephemeral: true,
embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_ROLE(message)]
});
} }
catch (err) { } else if (payload.a === 'deny') {
return interaction.reply({ ephemeral: true, embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_ROLE(message)] });
}
}
else if (payload.a === 'deny') {
try { try {
await requesterMember.kick(); 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 }); await message.edit({ components: [], embeds: embed });
} catch (err) {
return interaction.reply({
ephemeral: true,
embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_KICK(message)]
});
} }
catch (err) { } else if (payload.a === 'ban') {
return interaction.reply({ ephemeral: true, embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_KICK(message)] });
}
}
else if (payload.a === 'ban') {
try { try {
await requesterMember.ban({ await requesterMember.ban({
reason: `Membership Screening, action issued by ${interaction.user.username}#${interaction.user.discriminator} (${interaction.user.id})` 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 }); await message.edit({ components: [], embeds: embed });
} } catch (err) {
catch (err) { return interaction.reply({
return interaction.reply({ ephemeral: true, embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_BAN(message)] }); ephemeral: true,
embeds: [EMBEDS.CANNOT_PERFORM_ASSIGN_BAN(message)]
});
} }
} }
} }
} }
async run(data: HybridInteractionMessage, args: any) { async run(data: HybridInteractionMessage, args: any) {
const guild = data.getGuild(); const guild = data.getGuild();
const user = data.getUser(); const user = data.getUser();
const member = data.getMember(); const member = data.getMember();
@@ -280,24 +336,32 @@ export default class MembershipScreening extends DiscordModule {
if (!guild || !user || !member || !channel) return; 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; if (!PrismaGuild) return;
const funct = { const funct = {
enable: async (data: HybridInteractionMessage) => { enable: async (data: HybridInteractionMessage) => {
if (!PrismaGuild.MembershipScreening_Enabled) { 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) await Prisma.client.guild.update({
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PARAMETER(data.getRaw())] }); 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())]
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ENABLED(data.getRaw())] }); });
} } else
return await sendHybridInteractionMessageResponse(data, {
else embeds: [EMBEDS.ALREADY_ENABLED(data.getRaw())]
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ALREADY_ENABLED(data.getRaw())] }); });
}, },
disable: async (data: HybridInteractionMessage) => { disable: async (data: HybridInteractionMessage) => {
if (PrismaGuild.MembershipScreening_Enabled) { if (PrismaGuild.MembershipScreening_Enabled) {
@@ -306,111 +370,150 @@ export default class MembershipScreening extends DiscordModule {
data: { MembershipScreening_Enabled: false } data: { MembershipScreening_Enabled: false }
}); });
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.DISABLED(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
} embeds: [EMBEDS.DISABLED(data.getRaw())]
else });
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ALREADY_DISABLED(data.getRaw())] }); } else
return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.ALREADY_DISABLED(data.getRaw())]
});
}, },
setRole: async (data: HybridInteractionMessage) => { setRole: async (data: HybridInteractionMessage) => {
let role: Role | undefined; let role: Role | undefined;
if (data.isMessage()) { if (data.isMessage()) {
let _name: string; let _name: string;
if (typeof args[1] === 'undefined') 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; let __name = args;
__name.shift(); __name.shift();
_name = __name.join(" "); _name = __name.join(' ');
role = data.getMessage().mentions.roles.first() || guild.roles.cache.find(role => role.name === _name); role =
} data.getMessage().mentions.roles.first() ||
else if (data.isSlashCommand()) guild.roles.cache.find((role) => role.name === _name);
role = guild.roles.cache.find(role => role.id === data.getSlashCommand().options.getRole('role')?.id); } else if (data.isSlashCommand())
role = guild.roles.cache.find(
(role) => role.id === data.getSlashCommand().options.getRole('role')?.id
);
if (!role) 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) 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) => { setChannel: async (data: HybridInteractionMessage) => {
let mentionChannel; let mentionChannel;
if (data.isMessage()) { if (data.isMessage()) {
if (!args[1]) 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(); mentionChannel = data.getMessage().mentions.channels.first();
} } else if (data.isSlashCommand())
else if (data.isSlashCommand())
mentionChannel = data.getSlashCommand().options.getChannel('channel'); mentionChannel = data.getSlashCommand().options.getChannel('channel');
if (!mentionChannel) 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); let TargetChannel = guild.channels.cache.get(mentionChannel.id);
if (!TargetChannel) return; if (!TargetChannel) return;
if (TargetChannel instanceof ThreadChannel || TargetChannel.isThread()) 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()) 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]))) if (
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.BOT_NO_PERMISSION(data.getRaw(), TargetChannel)] }); !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 } }); await Prisma.client.guild.update({
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.CONFIGURED_CHANNEL(data.getRaw(), TargetChannel)] }); where: { id: guild.id },
data: { MembershipScreening_ApprovalChannel: mentionChannel.id }
});
return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.CONFIGURED_CHANNEL(data.getRaw(), TargetChannel)]
});
}, },
createMessage: async (data: HybridInteractionMessage) => { createMessage: async (data: HybridInteractionMessage) => {
if(data.isMessage()) if (data.isMessage())
return await sendMessage(channel, undefined, { embeds: [EMBEDS.CREATE_MESSAGE()] }); return await sendMessage(channel, undefined, {
else if(data.isSlashCommand()) { embeds: [EMBEDS.CREATE_MESSAGE()]
await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.MESSAGE_CREATED(data.getRaw())] }); });
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; let query;
if (!member.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) 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 (data.isMessage()) {
if (args.length === 0) 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(); query = args[0].toLowerCase();
} } else if (data.isSlashCommand()) query = args.getSubcommand();
else if (data.isSlashCommand())
query = args.getSubcommand();
switch (query) { switch (query) {
case "enable": case 'enable':
case "on": case 'on':
return await funct.enable(data); return await funct.enable(data);
case "disable": case 'disable':
case "off": case 'off':
return await funct.disable(data); return await funct.disable(data);
case "setrole": case 'setrole':
return await funct.setRole(data); return await funct.setRole(data);
case "setchannel": case 'setchannel':
return await funct.setChannel(data); return await funct.setChannel(data);
case "createmessage": case 'createmessage':
return await funct.createMessage(data); return await funct.createMessage(data);
} }
} }
async GuildMemberAdd(member: GuildMember) { async GuildMemberAdd(member: GuildMember) {
if (member.user.bot) return; if (member.user.bot) return;
const Guild = await Prisma.client.guild.findFirst({ where: { id: member.guild.id } }); 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; let channel = undefined;
try { 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) { } catch (err) {
// TODO: Handle channel not found error // TODO: Handle channel not found error
return; return;
@@ -434,8 +539,10 @@ export default class MembershipScreening extends DiscordModule {
description: `${member.user.username}#${member.user.discriminator} (${member.user.id})`, description: `${member.user.username}#${member.user.discriminator} (${member.user.id})`,
fields: [ fields: [
{ {
name: "Account Information", name: 'Account Information',
value: `Account age: <t:${Math.round(member.user.createdAt.getTime() / 1000)}:R>` value: `Account age: <t:${Math.round(
member.user.createdAt.getTime() / 1000
)}:R>`
} }
] ]
}); });
@@ -445,43 +552,49 @@ export default class MembershipScreening extends DiscordModule {
const row = new MessageActionRow() const row = new MessageActionRow()
.addComponents( .addComponents(
new MessageButton() new MessageButton()
.setCustomId(JSON.stringify({ .setCustomId(
JSON.stringify({
m: 'MembershipScreening', m: 'MembershipScreening',
a: 'approve', a: 'approve',
d: { d: {
requester: member.id requester: member.id
} }
})) })
)
.setEmoji('✅') .setEmoji('✅')
.setLabel(' Approve') .setLabel(' Approve')
.setStyle('SUCCESS'), .setStyle('SUCCESS')
) )
.addComponents( .addComponents(
new MessageButton() new MessageButton()
.setCustomId(JSON.stringify({ .setCustomId(
JSON.stringify({
m: 'MembershipScreening', m: 'MembershipScreening',
a: 'deny', a: 'deny',
d: { d: {
requester: member.id requester: member.id
} }
})) })
)
.setEmoji('⛔') .setEmoji('⛔')
.setLabel(' Deny and kick') .setLabel(' Deny and kick')
.setStyle('DANGER'), .setStyle('DANGER')
) )
.addComponents( .addComponents(
new MessageButton() new MessageButton()
.setCustomId(JSON.stringify({ .setCustomId(
JSON.stringify({
m: 'MembershipScreening', m: 'MembershipScreening',
a: 'ban', a: 'ban',
d: { d: {
requester: member.id requester: member.id
} }
})) })
)
.setEmoji('🔪') .setEmoji('🔪')
.setLabel(' Vision Hunt Decree (Ban)') .setLabel(' Vision Hunt Decree (Ban)')
.setStyle('DANGER'), .setStyle('DANGER')
) );
await channel.send({ content: '\u200b', embeds: [embed], components: [row] }); await channel.send({ content: '\u200b', embeds: [embed], components: [row] });
} }
@@ -489,12 +602,11 @@ export default class MembershipScreening extends DiscordModule {
private isJsonValid(jsonString: string) { private isJsonValid(jsonString: string) {
try { try {
let o = JSON.parse(jsonString); let o = JSON.parse(jsonString);
if (o && typeof o === "object") { if (o && typeof o === 'object') {
return true; return true;
//return o; //return o;
} }
} } catch (e) {}
catch (e) { }
return false; return false;
} }
+59 -36
View File
@@ -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 Configuration from '../providers/Configuration';
import { makeSuccessEmbed, makeProcessingEmbed, sendHybridInteractionMessageResponse } from "../utils/DiscordMessage"; import DiscordProvider from '../providers/Discord';
import Environment from '../providers/Environment';
import DiscordProvider from "../providers/Discord"; import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule';
import NodePing from "ping"; import {
import { Promise } from "bluebird"; makeSuccessEmbed,
import os from "os"; makeProcessingEmbed,
import Environment from "../providers/Environment"; sendHybridInteractionMessageResponse
import Configuration from "../providers/Configuration"; } from '../utils/DiscordMessage';
enum MeasureType { enum MeasureType {
Ping = "ping", Ping = 'ping',
DiscordHTTPPing = "discordhttp", DiscordHTTPPing = 'discordhttp',
DiscordWebsocket = "discordwebsocket" DiscordWebsocket = 'discordwebsocket'
} }
const EMBEDS = { const EMBEDS = {
@@ -22,23 +26,22 @@ const EMBEDS = {
icon: '🌎', icon: '🌎',
title: `Network performance`, title: `Network performance`,
description: description, description: description,
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
}, },
PINGING: (data: HybridInteractionMessage) => { PINGING: (data: HybridInteractionMessage) => {
return makeProcessingEmbed({ return makeProcessingEmbed({
icon: data.isMessage() ? undefined : '⌛', icon: data.isMessage() ? undefined : '⌛',
title: `Measuring network performance`, 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 { export default class Ping extends DiscordModule {
public id = 'Discord_Ping';
public id = "Discord_Ping"; public commands = ['ping'];
public commands = ["ping"]; public commandInteractionName = 'ping';
public commandInteractionName = "ping";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -49,20 +52,22 @@ export default class Ping extends DiscordModule {
} }
async run(data: HybridInteractionMessage, args: any) { async run(data: HybridInteractionMessage, args: any) {
let placeholder: (HybridInteractionMessage | undefined); let placeholder: HybridInteractionMessage | undefined;
let beforeEditDate = Date.now(); let beforeEditDate = Date.now();
let _placeholder = await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PINGING(data)] }); let _placeholder = await sendHybridInteractionMessageResponse(data, {
if (_placeholder) embeds: [EMBEDS.PINGING(data)]
placeholder = new HybridInteractionMessage(_placeholder); });
if (_placeholder) placeholder = new HybridInteractionMessage(_placeholder);
let afterEditDate = Date.now(); let afterEditDate = Date.now();
let finalString = []; let finalString = [];
await Promise.map(Configuration.getConfig("Ping"), (entry: any) => { await Promise.map(
Configuration.getConfig('Ping'),
(entry: any) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
let stringCurrent = `${entry.title}`; let stringCurrent = `${entry.title}`;
@@ -70,19 +75,27 @@ export default class Ping extends DiscordModule {
const res = await NodePing.promise.probe(entry.host!, { min_reply: 4 }); const res = await NodePing.promise.probe(entry.host!, { min_reply: 4 });
if (!res.alive) { if (!res.alive) {
stringCurrent += "Failed"; stringCurrent += 'Failed';
return finalString.push(stringCurrent); return finalString.push(stringCurrent);
} }
if (res.avg === 'unknown' || res.min === 'unknown' || res.max === 'unknown') { if (
stringCurrent += "Failed"; res.avg === 'unknown' ||
res.min === 'unknown' ||
res.max === 'unknown'
) {
stringCurrent += 'Failed';
return finalString.push(stringCurrent); return finalString.push(stringCurrent);
} }
stringCurrent += `${parseFloat(res.avg).toFixed(1)}ms (${parseFloat(res.min).toFixed(1)}ms - ${parseFloat(res.max).toFixed(1)}ms)`; stringCurrent += `${parseFloat(res.avg).toFixed(1)}ms (${parseFloat(
res.min
).toFixed(1)}ms - ${parseFloat(res.max).toFixed(1)}ms)`;
finalString.push(stringCurrent); finalString.push(stringCurrent);
} else if (entry.type === MeasureType.DiscordWebsocket) { } else if (entry.type === MeasureType.DiscordWebsocket) {
stringCurrent += `${Math.round(DiscordProvider.client.ws.ping).toFixed(1)}ms`; stringCurrent += `${Math.round(DiscordProvider.client.ws.ping).toFixed(
1
)}ms`;
finalString.push(stringCurrent); finalString.push(stringCurrent);
} else if (entry.type === MeasureType.DiscordHTTPPing) { } else if (entry.type === MeasureType.DiscordHTTPPing) {
stringCurrent += `${Math.abs(afterEditDate - beforeEditDate).toFixed(1)}ms`; stringCurrent += `${Math.abs(afterEditDate - beforeEditDate).toFixed(1)}ms`;
@@ -91,15 +104,25 @@ export default class Ping extends DiscordModule {
resolve(); resolve();
}); });
}, { concurrency: 5 }); },
{ concurrency: 5 }
);
finalString.push(""); finalString.push('');
finalString.push("💻 Running on " + `${os.hostname()}${Environment.get().NODE_ENV === "development" ? ' / Development Environment' : ''}`); finalString.push(
'💻 Running on ' +
`${os.hostname()}${
Environment.get().NODE_ENV === 'development' ? ' / Development Environment' : ''
}`
);
if (data.isSlashCommand()) 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()) 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'))] });
} }
} }
+51 -33
View File
@@ -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 DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule';
import { makeSuccessEmbed, sendHybridInteractionMessageResponse, makeErrorEmbed, makeInfoEmbed } from "../utils/DiscordMessage"; import {
makeSuccessEmbed,
sendHybridInteractionMessageResponse,
makeErrorEmbed,
makeInfoEmbed
} from '../utils/DiscordMessage';
const EMBEDS = { const EMBEDS = {
SAY_INFO: (data: Message | Interaction) => { SAY_INFO: (data: Message | Interaction) => {
return makeInfoEmbed ({ return makeInfoEmbed({
title: 'Say', title: 'Say',
description: `Make me say something!`, description: `Make me say something!`,
fields: [ fields: [
@@ -14,28 +19,27 @@ const EMBEDS = {
value: '``Your message``' value: '``Your message``'
} }
], ],
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
}, },
NO_PERMISSION: (data: Message | Interaction) => { NO_PERMISSION: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'You need ``VIEW_CHANNEL, SEND_MESSAGES and MANAGE_CHANNELS`` permission on this guild!', 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) => { SUCCESSFULLY_SAID: (data: Message | Interaction) => {
return makeSuccessEmbed ({ return makeSuccessEmbed({
title: 'Successfully said', 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 { export default class Say extends DiscordModule {
public id = 'Discord_Say';
public id = "Discord_Say"; public commands = ['say'];
public commands = ["say"]; public commandInteractionName = 'say';
public commandInteractionName = "say";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -46,41 +50,55 @@ export default class Say extends DiscordModule {
} }
async run(data: HybridInteractionMessage, args: any) { async run(data: HybridInteractionMessage, args: any) {
let query; let query;
if(data.isMessage()) { if (data.isMessage()) {
const message = data.getMessage(); 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])) if (
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] }); !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) if (args.length === 0)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SAY_INFO(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.SAY_INFO(data.getRaw())]
});
query = args.join(" "); query = args.join(' ');
} } else if (data.isSlashCommand()) {
else if(data.isSlashCommand()) {
const interaction = data.getSlashCommand(); const interaction = data.getSlashCommand();
if(!data.getGuild()!.members.cache.get(interaction.user.id)?.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) if (
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PERMISSION(data.getRaw())] }); !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'); query = interaction.options.getString('message');
} }
if(data.isSlashCommand() && data.getChannel()) { if (data.isSlashCommand() && data.getChannel()) {
await data.getChannel()!.send({ content: query }); await data.getChannel()!.send({ content: query });
await data.getMessageComponentInteraction().reply({ ephemeral: true, embeds: [EMBEDS.SUCCESSFULLY_SAID(data.getRaw())] }); await data
} .getMessageComponentInteraction()
else if(data.isMessage()) { .reply({ ephemeral: true, embeds: [EMBEDS.SUCCESSFULLY_SAID(data.getRaw())] });
} else if (data.isMessage()) {
const message = data.getMessage(); const message = data.getMessage();
if(message.deletable) if (message.deletable) await message.delete();
await message.delete();
await data.getChannel()!.send({ content: query }); await data.getChannel()!.send({ content: query });
} }
} }
} }
+272 -147
View File
@@ -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 DiscordProvider from '../providers/Discord';
import { makeInfoEmbed, makeErrorEmbed, makeSuccessEmbed, makeProcessingEmbed, sendHybridInteractionMessageResponse } from "../utils/DiscordMessage"; import Prisma from '../providers/Prisma';
import DiscordProvider from "../providers/Discord"; import Cache from '../providers/Cache';
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 = { const EMBEDS = {
SETTINGS_INFO: (data: Message | Interaction) => { SETTINGS_INFO: (data: Message | Interaction) => {
@@ -17,133 +31,143 @@ const EMBEDS = {
value: '``setPrefix`` ``setEnableServiceAnnouncement`` ``setServiceAnnouncementChannel``' value: '``setPrefix`` ``setEnableServiceAnnouncement`` ``setServiceAnnouncementChannel``'
} }
], ],
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
}, },
PROCESSING: (data: HybridInteractionMessage) => { PROCESSING: (data: HybridInteractionMessage) => {
return makeProcessingEmbed({ return makeProcessingEmbed({
icon: (data.isMessage()) ? undefined : '⌛', icon: data.isMessage() ? undefined : '⌛',
title: `Performing actions`, title: `Performing actions`,
user: data.getUser() user: data.getUser()
}); });
}, },
NO_PERMISSION: (data: Message | Interaction) => { NO_PERMISSION: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'You need ``ADMINISTRATOR`` permission on this guild!', 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) => { NO_PREFIX_PROVIDED: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'No prefix provided', 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) => { SERVICE_ANNOUNCEMENT_INVALID_STATUS: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'Invalid status, Use ``true`` or ``false``', 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) => { NO_SERVICE_ANNOUNCEMENT_STATUS_PROVIDED: async (data: Message | Interaction) => {
let GuildCache = await Cache.getGuild(data.guild!.id); let GuildCache = await Cache.getGuild(data.guild!.id);
// TODO: Better error handling // TODO: Better error handling
if(typeof GuildCache === 'undefined') if (typeof GuildCache === 'undefined') throw new Error('Guild not found');
throw new Error('Guild not found');
return makeInfoEmbed ({ return makeInfoEmbed({
title: 'Service Announcement', title: 'Service Announcement',
description: `Service Announcement is ${GuildCache.ServiceAnnouncement_Enabled ? "**enabled**" : "**disabled**"} on this server`, description: `Service Announcement is ${
user: (data instanceof Interaction) ? data.user : data.author GuildCache.ServiceAnnouncement_Enabled ? '**enabled**' : '**disabled**'
} on this server`,
user: data instanceof Interaction ? data.user : data.author
}); });
}, },
PREFIX_TOO_LONG: (data: Message | Interaction) => { PREFIX_TOO_LONG: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'Prefix too long', title: 'Prefix too long',
description: `I bet you can't even remember that`, 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) => { PREFIX_IS_MENTION: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'Prefix cannot be mention of me', title: 'Prefix cannot be mention of me',
description: `You can already call me by mentioning me. I got that covered, don't worry`, 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) => { PREFIX_UPDATED: (data: Message | Interaction, newPrefix: string) => {
return makeSuccessEmbed ({ return makeSuccessEmbed({
title: 'Prefix Updated', title: 'Prefix Updated',
description: `From now onwards, I shall be called by using \`\`${newPrefix}\`\``, 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) => { SERVICE_ANNOUNCEMENT_STATUS_UPDATED: (data: Message | Interaction, newStatus: boolean) => {
return makeSuccessEmbed ({ return makeSuccessEmbed({
title: `Service Announcement is now ${newStatus ? "enabled" : "disabled"}`, title: `Service Announcement is now ${newStatus ? 'enabled' : 'disabled'}`,
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
}, },
SERVICE_ANNOUNCEMENT_STATUS_ALREADY_SET: (data: Message | Interaction, status: boolean) => { SERVICE_ANNOUNCEMENT_STATUS_ALREADY_SET: (data: Message | Interaction, status: boolean) => {
return makeInfoEmbed ({ return makeInfoEmbed({
title: `Service Announcement is already ${status ? "enabled" : "disabled"}`, title: `Service Announcement is already ${status ? 'enabled' : 'disabled'}`,
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
}, },
SERVICE_ANNOUNCEMENT_NO_PARAMETER: (data: Message | Interaction) => { SERVICE_ANNOUNCEMENT_NO_PARAMETER: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'Missing parameter', title: 'Missing parameter',
description: `You must define service announcement channel to enable this feature`, 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) => { NO_CHANNEL_MENTIONED: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'No channel mentioned', 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) => { NO_CHANNEL_FOUND: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'Cannot find that channel', 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) => { INVALID_CHANNEL: (data: Message | Interaction, channel: GuildChannel) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'Invalid channel type, only TextChannel is supported', title: 'Invalid channel type, only TextChannel is supported',
description: '``' + channel.name +'``' + ' is not a text channel', 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: (
return makeErrorEmbed ({ data: Message | Interaction,
channel: GuildChannel | ThreadChannel
) => {
return makeErrorEmbed({
title: 'Thread channel is not supported', title: 'Thread channel is not supported',
description: '``' + channel.name +'``' + ' is a thread channel. Please use a regular text channel', description:
user: (data instanceof Interaction) ? data.user : data.author '``' +
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) => { BOT_NO_PERMISSION: (data: Message | Interaction, channel: GuildChannel) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: `I don't have permission`, title: `I don't have permission`,
description: 'I cannot access/send message in ' + '``' + channel.name +'``', 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
}); });
}, },
SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL: (data: Message | Interaction, channel: GuildChannel) => { SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL: (
return makeSuccessEmbed ({ data: Message | Interaction,
channel: GuildChannel
) => {
return makeSuccessEmbed({
title: 'Configured Service Announcement Channel', 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 { export default class Settings extends DiscordModule {
public id = 'Discord_Settings';
public id = "Discord_Settings"; public commands = ['settings'];
public commands = ["settings"]; public commandInteractionName = 'settings';
public commandInteractionName = "settings";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -154,175 +178,276 @@ export default class Settings extends DiscordModule {
} }
async run(data: HybridInteractionMessage, args: any) { async run(data: HybridInteractionMessage, args: any) {
const Guild = await Prisma.client.guild.findFirst({ where: { id: data.getGuild()!.id } });
const Guild = await Prisma.client.guild.findFirst({ where: { id: data.getGuild()!.id }}) if (!Guild) return;
if(!Guild) return;
const funct = { const funct = {
setPrefix: async(data: HybridInteractionMessage) => { setPrefix: async (data: HybridInteractionMessage) => {
let member = data.getMember(); let member = data.getMember();
if(!member) return; if (!member) return;
if (!member.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) 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; let newPrefix: string | null | undefined;
if(data.isMessage()) { if (data.isMessage()) {
let _name: string; let _name: string;
if(typeof args[1] === 'undefined') if (typeof args[1] === 'undefined')
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PREFIX_PROVIDED(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.NO_PREFIX_PROVIDED(data.getRaw())]
});
let __name = args; let __name = args;
__name.shift(); __name.shift();
_name = __name.join(" "); _name = __name.join(' ');
newPrefix = _name; newPrefix = _name;
} } else if (data.isSlashCommand())
else if(data.isSlashCommand())
newPrefix = data.getSlashCommand().options.getString('prefix'); newPrefix = data.getSlashCommand().options.getString('prefix');
if(!newPrefix) if (!newPrefix)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_PREFIX_PROVIDED(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.NO_PREFIX_PROVIDED(data.getRaw())]
});
if(newPrefix.length > 200) if (newPrefix.length > 200)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PREFIX_TOO_LONG(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.PREFIX_TOO_LONG(data.getRaw())]
});
if(newPrefix.startsWith(`<@!${DiscordProvider.client.user?.id}>`)) if (newPrefix.startsWith(`<@!${DiscordProvider.client.user?.id}>`))
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PREFIX_IS_MENTION(data.getRaw())] }); 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)] }); let _placeholder = await sendHybridInteractionMessageResponse(data, {
if (_placeholder) embeds: [EMBEDS.PROCESSING(data)]
placeholder = new HybridInteractionMessage(_placeholder); });
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); Cache.updateGuildCache(data.getGuild()!.id);
if(data && data.isMessage() && placeholder && placeholder.isMessage()) if (data && data.isMessage() && placeholder && placeholder.isMessage())
return placeholder.getMessage().edit({ embeds: [EMBEDS.PREFIX_UPDATED(data.getRaw(), newPrefix)] }); return placeholder
else if(data.isSlashCommand()) .getMessage()
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.PREFIX_UPDATED(data.getRaw(), newPrefix)]}, true); .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(); let member = data.getMember();
if(!member) return; if (!member) return;
if (!member.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) 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; let newStatus: string | null | undefined;
if(data.isMessage()) { if (data.isMessage()) {
let _name: string; let _name: string;
if(typeof args[1] === 'undefined') if (typeof args[1] === 'undefined')
return await sendHybridInteractionMessageResponse(data, { embeds: [await EMBEDS.NO_SERVICE_ANNOUNCEMENT_STATUS_PROVIDED(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [
await EMBEDS.NO_SERVICE_ANNOUNCEMENT_STATUS_PROVIDED(data.getRaw())
]
});
let __name = args; let __name = args;
__name.shift(); __name.shift();
_name = __name.join(" "); _name = __name.join(' ');
newStatus = _name; newStatus = _name;
} } else if (data.isSlashCommand())
else if(data.isSlashCommand())
newStatus = data.getSlashCommand().options.getString('status')!; newStatus = data.getSlashCommand().options.getString('status')!;
if(!newStatus) if (!newStatus)
return await sendHybridInteractionMessageResponse(data, { embeds: [await EMBEDS.NO_SERVICE_ANNOUNCEMENT_STATUS_PROVIDED(data.getRaw())] }); 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())) if (
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_INVALID_STATUS(data.getRaw())] }); !['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); await Cache.updateGuildCache(data.getGuild()!.id);
let GuildCache = await Cache.getGuild(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) if (GuildCache?.ServiceAnnouncement_Enabled === newStatusBool)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_ALREADY_SET(data.getRaw(), newStatusBool)] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [
EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_ALREADY_SET(
data.getRaw(),
newStatusBool
)
]
});
if(GuildCache?.ServiceAnnouncement_Channel === null) if (GuildCache?.ServiceAnnouncement_Channel === null)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_NO_PARAMETER(data.getRaw())] }); 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( await Prisma.client.guild.update({
{ where: { id: data.getGuild()!.id }, where: { id: data.getGuild()!.id },
data: { data: {
ServiceAnnouncement_Enabled: newStatusBool ServiceAnnouncement_Enabled: newStatusBool
} }
}); });
Cache.updateGuildCache(data.getGuild()!.id); Cache.updateGuildCache(data.getGuild()!.id);
if(data.isMessage()) if (data.isMessage())
return await (placeholder as Message).edit({ embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_UPDATED(data.getRaw(), newStatusBool)]}); return await (placeholder as Message).edit({
else if(data.isSlashCommand()) embeds: [
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_STATUS_UPDATED(data.getRaw(), newStatusBool)]}, true); 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
)
]
}, },
setServiceAnnouncementChannel: async(data: HybridInteractionMessage) => { true
);
},
setServiceAnnouncementChannel: async (data: HybridInteractionMessage) => {
let member = data.getMember(); let member = data.getMember();
if(!member) return; if (!member) return;
if (!member.permissions.has([Permissions.FLAGS.ADMINISTRATOR])) 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; let channel;
if(data.isMessage()) { if (data.isMessage()) {
if(typeof args[1] === 'undefined') if (typeof args[1] === 'undefined')
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_CHANNEL_MENTIONED(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.NO_CHANNEL_MENTIONED(data.getRaw())]
});
channel = data.getMessage().mentions.channels.first(); channel = data.getMessage().mentions.channels.first();
} } else if (data.isSlashCommand())
else if(data.isSlashCommand())
channel = data.getSlashCommand().options.getChannel('channel'); channel = data.getSlashCommand().options.getChannel('channel');
if(!channel) if (!channel)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_CHANNEL_FOUND(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.NO_CHANNEL_FOUND(data.getRaw())]
});
let TargetChannel = data.getGuild()!.channels.cache.get(channel.id); 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()) 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()) 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(!(data.getGuild()!.me?.permissionsIn(TargetChannel).has([Permissions.FLAGS.SEND_MESSAGES, Permissions.FLAGS.VIEW_CHANNEL]))) if (
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.BOT_NO_PERMISSION(data.getRaw(), TargetChannel)] }); !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()) if (data.isMessage())
return await (placeholder as Message).edit({ embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL(data.getRaw(), TargetChannel)]}); return await (placeholder as Message).edit({
else if(data.isSlashCommand()) embeds: [
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_CONFIGURED_CHANNEL(data.getRaw(), TargetChannel)]}, true); 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; let query;
if(data.isMessage()) { if (data.isMessage()) {
if(args.length === 0) if (args.length === 0)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SETTINGS_INFO(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.SETTINGS_INFO(data.getRaw())]
});
query = args[0].toLowerCase(); query = args[0].toLowerCase();
} } else if (data.isSlashCommand()) {
else if(data.isSlashCommand()) {
query = args.getSubcommand(); query = args.getSubcommand();
} }
switch(query) { switch (query) {
case "info": case 'info':
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SETTINGS_INFO(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
case "setprefix": embeds: [EMBEDS.SETTINGS_INFO(data.getRaw())]
});
case 'setprefix':
return await funct.setPrefix(data); return await funct.setPrefix(data);
case "setenableserviceannouncement": case 'setenableserviceannouncement':
return await funct.setEnableServiceAnnouncement(data); return await funct.setEnableServiceAnnouncement(data);
case "setserviceannouncementchannel": case 'setserviceannouncementchannel':
return await funct.setServiceAnnouncementChannel(data); return await funct.setServiceAnnouncementChannel(data);
} }
} }
} }
+24 -16
View File
@@ -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 DiscordProvider from '../providers/Discord';
import { sendHybridInteractionMessageResponse, makeInfoEmbed } from "../utils/DiscordMessage";
import DiscordProvider from "../providers/Discord"; import DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule';
import os from "os-utils"; import { sendHybridInteractionMessageResponse, makeInfoEmbed } from '../utils/DiscordMessage';
const EMBEDS = { const EMBEDS = {
STATS_INFO: (data: Message | Interaction) => { STATS_INFO: (data: Message | Interaction) => {
let message;
return makeInfoEmbed({ return makeInfoEmbed({
title: `Stats`, title: `Stats`,
icon: '📊', icon: '📊',
@@ -16,25 +15,32 @@ const EMBEDS = {
fields: [ fields: [
{ {
name: '🌐 Users', 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 inline: true
}, },
{ {
name: '🟢 Uptime since', name: '🟢 Uptime since',
value: `System: <t:${(Math.round(new Date().getTime() / 1000)) - Math.round(os.sysUptime())}:R>\nProcess: <t:${(Math.round(new Date().getTime() / 1000)) - Math.round(os.processUptime())}:R>`, value: `System: <t:${
Math.round(new Date().getTime() / 1000) - Math.round(os.sysUptime())
}:R>\nProcess: <t:${
Math.round(new Date().getTime() / 1000) - Math.round(os.processUptime())
}:R>`,
inline: true inline: true
} }
], ],
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
} }
} };
export default class Stats extends DiscordModule { export default class Stats extends DiscordModule {
public id = 'Discord_Stats';
public id = "Discord_Stats"; public commands = ['stats'];
public commands = ["stats"]; public commandInteractionName = 'stats';
public commandInteractionName = "stats";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -45,6 +51,8 @@ export default class Stats extends DiscordModule {
} }
async run(data: HybridInteractionMessage, args: any) { 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())]
});
} }
} }
+91 -64
View File
@@ -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 DiscordModule, { HybridInteractionMessage } from '../utils/DiscordModule';
import { sendHybridInteractionMessageResponse, makeErrorEmbed, makeInfoEmbed } from "../utils/DiscordMessage"; import {
import { getColorFromURL } from "color-thief-node"; sendHybridInteractionMessageResponse,
makeErrorEmbed,
makeInfoEmbed
} from '../utils/DiscordMessage';
const EMBEDS = { const EMBEDS = {
SAY_INFO: (data: Message | Interaction) => { SAY_INFO: (data: Message | Interaction) => {
return makeInfoEmbed ({ return makeInfoEmbed({
title: 'User Info', title: 'User Info',
description: `View info on discord user`, description: `View info on discord user`,
fields: [ fields: [
@@ -15,22 +19,21 @@ const EMBEDS = {
value: '``Discord user mention or id``' 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) => { USER_NOT_FOUND: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: 'That user cannot be found!', 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 { export default class UserInfo extends DiscordModule {
public id = 'Discord_UserInfo';
public id = "Discord_UserInfo"; public commands = ['userinfo'];
public commands = ["userinfo"]; public commandInteractionName = 'userinfo';
public commandInteractionName = "userinfo";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -43,47 +46,48 @@ export default class UserInfo extends DiscordModule {
async run(data: HybridInteractionMessage, args: any) { async run(data: HybridInteractionMessage, args: any) {
let query; let query;
if(data.isMessage()) { if (data.isMessage()) {
if(args.length === 0) if (args.length === 0)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SAY_INFO(data.getRaw())] }); 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; query = data.getMessage().mentions.users.first()?.id;
else else query = args[0];
query = args[0]; } else if (data.isSlashCommand())
}
else if(data.isSlashCommand())
query = data.getSlashCommand().options.getUser('user')?.id; query = data.getSlashCommand().options.getUser('user')?.id;
// Find the user want to look up // Find the user want to look up
let TargetMember = (await data.getGuild()!.members.fetch()).get(query); 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; let readableStatus: string;
switch(TargetMember.presence?.status) { switch (TargetMember.presence?.status) {
case "online": case 'online':
readableStatus = "🟢 Online"; readableStatus = '🟢 Online';
break; break;
case "idle": case 'idle':
readableStatus = "🌙 Idle"; readableStatus = '🌙 Idle';
break; break;
case "dnd": case 'dnd':
readableStatus = "⛔ Do not disturb"; readableStatus = '⛔ Do not disturb';
break; break;
case "offline": case 'offline':
readableStatus = "⚫ Offline"; readableStatus = '⚫ Offline';
break; break;
default: default:
readableStatus = "❓ Unknown"; readableStatus = '❓ Unknown';
break; break;
} }
const embed = makeInfoEmbed ({ const embed = makeInfoEmbed({
icon: '', icon: '',
title: `${TargetMember.user.tag}`, title: `${TargetMember.user.tag}`,
fields: [ fields: [
@@ -95,49 +99,73 @@ export default class UserInfo extends DiscordModule {
user: data.getUser() user: data.getUser()
}); });
if(TargetMember.presence?.activities) if (TargetMember.presence?.activities)
for(let activity of TargetMember.presence?.activities) { for (let activity of TargetMember.presence?.activities) {
if(activity.type === "CUSTOM") 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} embed.addField(
\u200b`, true); `${activity.name}`,
`${
!activity.emoji
? ''
: `${
activity.emoji?.identifier.startsWith('%')
? activity.emoji?.name
: '<' + activity.emoji?.identifier + '>'
}`
} ${activity.state === null ? '' : activity.state}
\u200b`,
true
);
else { else {
let emoji = ""; let emoji = '';
switch(activity.type) { switch (activity.type) {
case "PLAYING": case 'PLAYING':
emoji = "🕹 "; emoji = '🕹 ';
break; break;
case "STREAMING": case 'STREAMING':
emoji = "🔴 "; emoji = '🔴 ';
break; break;
case "LISTENING": case 'LISTENING':
emoji = "🎵 "; emoji = '🎵 ';
break; break;
case "WATCHING": case 'WATCHING':
emoji = "📺 "; emoji = '📺 ';
break; break;
case "COMPETING": case 'COMPETING':
emoji = "🌠 "; emoji = '🌠 ';
break; break;
} }
embed.addField( `${emoji}${activity.type.toLowerCase().charAt(0).toUpperCase() + activity.type.toLowerCase().slice(1)} ${activity.name}`, embed.addField(
`${emoji}${
activity.type.toLowerCase().charAt(0).toUpperCase() +
activity.type.toLowerCase().slice(1)
} ${activity.name}`,
`${activity.details === null ? '' : activity.details} `${activity.details === null ? '' : activity.details}
${activity.state === null ? '' : activity.state} ${activity.state === null ? '' : activity.state}
Since <t:${Math.round(new Date(activity.createdAt).getTime() / 1000)}:R> Since <t:${Math.round(new Date(activity.createdAt).getTime() / 1000)}:R>
\u200b`, true); \u200b`,
true
);
} }
} }
embed.addField(`📰 Information on this guild`, `${ embed.addField(
(TargetMember.joinedAt === null) ? 'Cannot determine joined date' : `Joined <t:${Math.round(TargetMember.joinedAt.getTime() / 1000)}:R>`} `📰 Information on this guild`,
${(TargetMember.id === data.getGuild()!.ownerId) ? 'Owner of this guild 👑' : ''} `${
`); TargetMember.joinedAt === null
? 'Cannot determine joined date'
: `Joined <t:${Math.round(TargetMember.joinedAt.getTime() / 1000)}:R>`
}
${TargetMember.id === data.getGuild()!.ownerId ? 'Owner of this guild 👑' : ''}
`
);
try { try {
const colorthief = await getColorFromURL(TargetMember.user.displayAvatarURL().replace('.webp', '.jpg')); const colorthief = await getColorFromURL(
TargetMember.user.displayAvatarURL().replace('.webp', '.jpg')
);
embed.setColor(colorthief); embed.setColor(colorthief);
} catch (err) { } catch (err) {}
}
embed.setThumbnail(TargetMember.user.displayAvatarURL()); embed.setThumbnail(TargetMember.user.displayAvatarURL());
embed.setAuthor({ embed.setAuthor({
@@ -146,6 +174,5 @@ export default class UserInfo extends DiscordModule {
}); });
return await sendHybridInteractionMessageResponse(data, { embeds: [embed] }); return await sendHybridInteractionMessageResponse(data, { embeds: [embed] });
} }
} }
+73 -47
View File
@@ -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 DiscordModule, { HybridInteractionMessage } from '../../utils/DiscordModule';
import { makeInfoEmbed, makeErrorEmbed, sendHybridInteractionMessageResponse, sendMessageOrInteractionResponse } from "../../utils/DiscordMessage"; import {
import DiscordProvider from "../../providers/Discord"; makeInfoEmbed,
import DiscordMusicPlayer from "../../providers/DiscordMusicPlayer"; makeErrorEmbed,
import Users from "../../services/Users"; sendHybridInteractionMessageResponse
} from '../../utils/DiscordMessage';
import DiscordMusicPlayer from '../../providers/DiscordMusicPlayer';
import Users from '../../services/Users';
const EMBEDS = { const EMBEDS = {
DEBUG_INFO: (data: Message | Interaction) => { DEBUG_INFO: (data: Message | Interaction) => {
@@ -17,14 +28,14 @@ const EMBEDS = {
value: '``invalidInteraction`` ``crashMusicPlayer`` ``crash`` ``activemusicplayer``' 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) => { INVALID_TEST: (data: Message | Interaction) => {
return makeInfoEmbed({ return makeInfoEmbed({
title: 'Click button below to test invalid interaction', title: 'Click button below to test invalid interaction',
description: `The interaction will be failed`, 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) => { CRASHING: (data: Message | Interaction) => {
@@ -32,30 +43,29 @@ const EMBEDS = {
icon: '💀', icon: '💀',
title: 'Crashing myself', title: 'Crashing myself',
description: `Sayonara.... cruel world`, 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<any, any>) => { ACTIVE_MUSIC_PLAYERS: (data: Message | Interaction, totalplayers: Map<any, any>) => {
return makeInfoEmbed({ return makeInfoEmbed({
icon: '🎵', icon: '🎵',
title: `Total active music players: ${totalplayers.size}`, 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) => { NOT_DEVELOPER: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Developer only', title: 'Developer only',
description: `This command is restricted to the developers 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 { export default class Debug extends DiscordModule {
public id = 'Discord_Developer_Debug';
public id = "Discord_Developer_Debug"; public commands = ['debug', 'dbg'];
public commands = ["debug", "dbg"]; public commandInteractionName = 'debug';
public commandInteractionName = "debug";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -66,84 +76,100 @@ export default class Debug extends DiscordModule {
} }
async GuildButtonInteractionCreate(data: ButtonInteraction) { 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 hybridData = new HybridInteractionMessage(data);
const user = hybridData.getUser(); const user = hybridData.getUser();
if(!user) return; if (!user) return;
if (!Users.isDeveloper(user.id)) 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 () => { setTimeout(async () => {
await sendHybridInteractionMessageResponse(hybridData, { content: 'dev_make_invalid_interaction' }); await sendHybridInteractionMessageResponse(hybridData, {
}, 7 * 1000) content: 'dev_make_invalid_interaction'
});
}, 7 * 1000);
} }
async run(data: HybridInteractionMessage, args: any) { async run(data: HybridInteractionMessage, args: any) {
const guild = data.getGuild(); const guild = data.getGuild();
const user = data.getUser(); const user = data.getUser();
const channel = data.getChannel(); const channel = data.getChannel();
if(!guild || !user || !channel) return; if (!guild || !user || !channel) return;
if (!Users.isDeveloper(user.id)) 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 = { const funct = {
crash: async (data: HybridInteractionMessage) => { crash: async (data: HybridInteractionMessage) => {
await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.CRASHING(data.getRaw())] }); await sendHybridInteractionMessageResponse(data, {
throw new Error("Manually crashed by debug command"); embeds: [EMBEDS.CRASHING(data.getRaw())]
});
throw new Error('Manually crashed by debug command');
}, },
crashMusicPlayer: async (data: HybridInteractionMessage) => { crashMusicPlayer: async (data: HybridInteractionMessage) => {
const instance = DiscordMusicPlayer.getGuildInstance(guild.id); const instance = DiscordMusicPlayer.getGuildInstance(guild.id);
if(!instance) return; if (!instance) return;
instance._fake_error_on_player(); instance._fake_error_on_player();
}, },
activeMusicPlayer: async (data: HybridInteractionMessage) => { 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) => { invalidInteraction: async (data: HybridInteractionMessage) => {
const row = new MessageActionRow().addComponents(
const row = new MessageActionRow()
.addComponents(
new MessageButton() new MessageButton()
.setEmoji('😥') .setEmoji('😥')
.setLabel('Make invalid interaction (Wait 7 seconds, check error in console or logs)') .setLabel(
.setCustomId('dev_make_invalid_interaction') 'Make invalid interaction (Wait 7 seconds, check error in console or logs)'
.setStyle('PRIMARY'),
) )
await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_TEST(data.getRaw())], components: [row] }); .setCustomId('dev_make_invalid_interaction')
} .setStyle('PRIMARY')
);
await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.INVALID_TEST(data.getRaw())],
components: [row]
});
} }
};
let query; let query;
if (data.isMessage()) { if (data.isMessage()) {
if (args.length === 0) 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(); query = args[0].toLowerCase();
} } else if (data.isSlashCommand()) {
else if (data.isSlashCommand()) {
query = args.getSubcommand(); query = args.getSubcommand();
} }
switch (query) { switch (query) {
case "info": case 'info':
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.DEBUG_INFO(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
case "crash": embeds: [EMBEDS.DEBUG_INFO(data.getRaw())]
});
case 'crash':
return await funct.crash(data); return await funct.crash(data);
case "invalidinteraction": case 'invalidinteraction':
return await funct.invalidInteraction(data); return await funct.invalidInteraction(data);
case "crashmusicplayer": case 'crashmusicplayer':
return await funct.crashMusicPlayer(data); return await funct.crashMusicPlayer(data);
case "activemusicplayer": case 'activemusicplayer':
return await funct.activeMusicPlayer(data); return await funct.activeMusicPlayer(data);
} }
} }
} }
+163 -95
View File
@@ -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 { Guild } from '@prisma/client';
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 { Promise } from "bluebird"; import DiscordModule, { HybridInteractionMessage } from '../../utils/DiscordModule';
import fs from "fs"; import {
import path from "path"; makeInfoEmbed,
import Logger from "../../libs/Logger"; makeErrorEmbed,
import { Guild } from "@prisma/client"; 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 = { const EMBEDS = {
ANNOUNCEMENT_INFO: (data: Message | Interaction) => { ANNOUNCEMENT_INFO: (data: Message | Interaction) => {
@@ -23,14 +32,14 @@ const EMBEDS = {
value: '``reload`` ``previewNews`` ``sendNews`` ``previewMaintenance`` ``sendMaintenance`` ``previewMessage`` ``sendMessage`` ``previewAlert`` ``sendAlert``' 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) => { NOT_DEVELOPER: (data: Message | Interaction) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Developer only', title: 'Developer only',
description: `This command is restricted to the developers 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) => { MAKE_PAYLOAD: (payload: any) => {
@@ -38,10 +47,9 @@ const EMBEDS = {
payload.footer = { payload.footer = {
text: `${user?.username}`, text: `${user?.username}`,
iconURL: `${user?.displayAvatarURL()}?size=4096` iconURL: `${user?.displayAvatarURL()}?size=4096`
} };
if (!payload.timestamp) if (!payload.timestamp) payload.timestamp = new Date();
payload.timestamp = new Date();
if (payload.thumbnail?.url === 'bot_avatar') if (payload.thumbnail?.url === 'bot_avatar')
payload.thumbnail.url = `${user?.displayAvatarURL()}?size=4096`; payload.thumbnail.url = `${user?.displayAvatarURL()}?size=4096`;
@@ -50,95 +58,95 @@ const EMBEDS = {
payload.image.url = `${user?.displayAvatarURL()}?size=4096`; payload.image.url = `${user?.displayAvatarURL()}?size=4096`;
if (payload.description) 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) => { RELOADED: (data: Message | Interaction) => {
return makeSuccessEmbed({ return makeSuccessEmbed({
title: 'Service Announcement Configuration Reloaded', 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) => { RELOAD_ERROR: (data: Message | Interaction, error: string) => {
return makeErrorEmbed({ return makeErrorEmbed({
title: 'Unable to reload Service Announcement Configuration', title: 'Unable to reload Service Announcement Configuration',
description: `\`\`\`${error}\`\`\``, description: `\`\`\`${error}\`\`\``,
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
}, },
SENDING_SERVICE_ANNOUNCEMENT: (data: Message | Interaction) => { SENDING_SERVICE_ANNOUNCEMENT: (data: Message | Interaction) => {
return makeProcessingEmbed({ return makeProcessingEmbed({
title: 'Service Announcement', title: 'Service Announcement',
description: `Broadcasting 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) => { SERVICE_ANNOUNCEMENT_SENT: (data: Message | Interaction) => {
return makeSuccessEmbed({ return makeSuccessEmbed({
title: 'Service Announcement', title: 'Service Announcement',
description: `Broadcasted 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) => { SERVICE_ANNOUNCEMENT_SENT_WITH_ERRORS: (data: Message | Interaction) => {
return makeWarningEmbed({ return makeWarningEmbed({
title: 'Service Announcement', title: 'Service Announcement',
description: `Broadcasted Service Announcement with errors, check console for more info`, 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 = { let Announcements = {
News: { News: {
color: "#FAEDF0", color: '#FAEDF0',
title: '📰 Newsletter', title: '📰 Newsletter',
description: 'Some description here', description: 'Some description here',
thumbnail: { thumbnail: {
url: 'bot_avatar', url: 'bot_avatar'
} }
}, },
Maintenance: { Maintenance: {
color: "#383b80", color: '#383b80',
title: '🔧 Maintenance', title: '🔧 Maintenance',
description: 'The bot is going offline for maintenance.', description: 'The bot is going offline for maintenance.',
thumbnail: { thumbnail: {
url: 'bot_avatar', url: 'bot_avatar'
} }
}, },
Message: { Message: {
color: "#A1DE93", color: '#A1DE93',
title: '✉️Message', title: '✉️Message',
description: 'Some description here', description: 'Some description here',
thumbnail: { thumbnail: {
url: 'bot_avatar', url: 'bot_avatar'
} }
}, },
Alert: { Alert: {
color: "#EC255A", color: '#EC255A',
title: '🚨 Alert', title: '🚨 Alert',
description: 'Some description here', description: 'Some description here',
thumbnail: { thumbnail: {
url: 'bot_avatar', url: 'bot_avatar'
} }
} }
};
}
export default class ServiceAnnouncement extends DiscordModule { export default class ServiceAnnouncement extends DiscordModule {
public id = 'Discord_Developer_ServiceAnnouncement';
public id = "Discord_Developer_ServiceAnnouncement"; public commands = ['serviceannouncement'];
public commands = ["serviceannouncement"]; public commandInteractionName = 'serviceannouncement';
public commandInteractionName = "serviceannouncement";
async Init() { async Init() {
if (fs.existsSync(path.join(process.cwd(), 'configs/ServiceAnnouncement.json'))) { if (fs.existsSync(path.join(process.cwd(), 'configs/ServiceAnnouncement.json'))) {
try { 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()); const jsonData = JSON.parse(rawData.toString());
Announcements = jsonData; Announcements = jsonData;
} catch (err) { } catch (err) {
Logger.error("Unable to load custom ServiceAnnouncement config: " + err); Logger.error('Unable to load custom ServiceAnnouncement config: ' + err);
} }
} }
} }
@@ -152,42 +160,60 @@ export default class ServiceAnnouncement extends DiscordModule {
} }
async run(data: HybridInteractionMessage, args: any) { async run(data: HybridInteractionMessage, args: any) {
if (!Users.isDeveloper(data.getUser()!.id)) 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(); const channel = data.getChannel();
if(!channel) return; if (!channel) return;
const funct = { const funct = {
reload: async (data: HybridInteractionMessage) => { reload: async (data: HybridInteractionMessage) => {
if (fs.existsSync(path.join(process.cwd(), 'configs/ServiceAnnouncement.json'))) { if (fs.existsSync(path.join(process.cwd(), 'configs/ServiceAnnouncement.json'))) {
try { 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()); const jsonData = JSON.parse(rawData.toString());
Announcements = jsonData; Announcements = jsonData;
} catch (err: any) { } catch (err: any) {
Logger.error("Unable to load custom ServiceAnnouncement config: " + err); Logger.error('Unable to load custom ServiceAnnouncement config: ' + err);
return await sendMessage(channel, undefined, { embeds: [EMBEDS.RELOAD_ERROR(data.getRaw(), err)] }); return await sendMessage(channel, undefined, {
embeds: [EMBEDS.RELOAD_ERROR(data.getRaw(), err)]
});
} }
} else { } 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) => { 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) => { 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) => { 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) => { 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) => { publishServiceAnnouncement: async (data: HybridInteractionMessage, embed: any) => {
const Guilds = await Prisma.client.guild.findMany({}); const Guilds = await Prisma.client.guild.findMany({});
@@ -201,11 +227,15 @@ export default class ServiceAnnouncement extends DiscordModule {
let channel = undefined; let channel = undefined;
try { 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) { } catch (err) {
withError = true; withError = true;
const guildObject = DiscordProvider.client.guilds.cache.get(Guild.id); 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; continue;
} }
@@ -213,82 +243,120 @@ export default class ServiceAnnouncement extends DiscordModule {
toSend.set(Guild, channel); 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); let _placeholder = await sendHybridInteractionMessageResponse(
if (_placeholder) data,
placeholder = new HybridInteractionMessage(_placeholder); { embeds: [EMBEDS.SENDING_SERVICE_ANNOUNCEMENT(data.getRaw())] },
true
);
if (_placeholder) placeholder = new HybridInteractionMessage(_placeholder);
await Promise.map(toSend, element => { await Promise.map(
toSend,
(element) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
let Guild: Guild = element[0]; let Guild: Guild = element[0];
let Channel: TextChannel = element[1]; let Channel: TextChannel = element[1];
try { try {
const guildObject = DiscordProvider.client.guilds.cache.get(Guild.id); const guildObject = DiscordProvider.client.guilds.cache.get(
if (!guildObject) Guild.id
throw new Error('Guild not found'); );
Logger.info(`Sending Service Announcement to ${guildObject?.name} (${guildObject.id}) #${Channel.name} (${Channel.id})`); if (!guildObject) throw new Error('Guild not found');
await sendMessage(Channel, undefined, { embeds: [EMBEDS.MAKE_PAYLOAD(embed)] }) 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) { } catch (err) {
withError = true; withError = true;
const guildObject = DiscordProvider.client.guilds.cache.get(Guild.id); const guildObject = DiscordProvider.client.guilds.cache.get(
Guild.id
);
if (guildObject) if (guildObject)
Logger.info(`Unable to send Service Announcement to ${guildObject?.name} (${guildObject.id}) #${Channel.name} (${Channel.id})`); 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)); await new Promise((resolve) => setTimeout(resolve, 1000));
resolve(); resolve();
}); });
}, { concurrency: 2 }); },
{ concurrency: 2 }
);
if (withError) { if (withError) {
if(data && data.isMessage() && placeholder && placeholder.isMessage()) if (data && data.isMessage() && placeholder && placeholder.isMessage())
return placeholder.getMessage().edit({ embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT_WITH_ERRORS(data.getRaw())] }); return placeholder
else if(data.isSlashCommand()) .getMessage()
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT_WITH_ERRORS(data.getRaw())] }, true); .edit({
} embeds: [
else { EMBEDS.SERVICE_ANNOUNCEMENT_SENT_WITH_ERRORS(data.getRaw())
if(data && data.isMessage() && placeholder && placeholder.isMessage()) ]
return placeholder.getMessage().edit({ embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT(data.getRaw())] }); });
else if(data.isSlashCommand()) else if (data.isSlashCommand())
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.SERVICE_ANNOUNCEMENT_SENT(data.getRaw())] }, true); 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; let query;
if (data.isMessage()) { if (data.isMessage()) {
if (args.length === 0) 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(); query = args[0].toLowerCase();
} } else if (data.isSlashCommand()) {
else if (data.isSlashCommand()) {
query = args.getSubcommand(); query = args.getSubcommand();
} }
switch (query) { switch (query) {
case "info": case 'info':
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.ANNOUNCEMENT_INFO(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
case "reload": embeds: [EMBEDS.ANNOUNCEMENT_INFO(data.getRaw())]
});
case 'reload':
return await funct.reload(data); return await funct.reload(data);
case "previewnews": case 'previewnews':
return await funct.previewNews(data); return await funct.previewNews(data);
case "previewmaintenance": case 'previewmaintenance':
return await funct.previewMaintenance(data); return await funct.previewMaintenance(data);
case "previewmessage": case 'previewmessage':
return await funct.previewMessage(data); return await funct.previewMessage(data);
case "previewalert": case 'previewalert':
return await funct.previewAlert(data); return await funct.previewAlert(data);
case "sendnews": case 'sendnews':
return await funct.publishServiceAnnouncement(data, Announcements.News); return await funct.publishServiceAnnouncement(data, Announcements.News);
case "sendmaintenance": case 'sendmaintenance':
return await funct.publishServiceAnnouncement(data, Announcements.Maintenance); return await funct.publishServiceAnnouncement(data, Announcements.Maintenance);
case "sendmessage": case 'sendmessage':
return await funct.publishServiceAnnouncement(data, Announcements.Message); return await funct.publishServiceAnnouncement(data, Announcements.Message);
case "sendalert": case 'sendalert':
return await funct.publishServiceAnnouncement(data, Announcements.Alert); return await funct.publishServiceAnnouncement(data, Announcements.Alert);
} }
} }
+230 -153
View File
@@ -1,16 +1,27 @@
import DiscordModule, { HybridInteractionMessage } from "../utils/DiscordModule"; import {
Message,
import { Message, MessageActionRow, MessageButton, Interaction, CommandInteraction } from "discord.js"; MessageActionRow,
import { makeInfoEmbed, makeErrorEmbed, sendHybridInteractionMessageResponse } from "../utils/DiscordMessage"; MessageButton,
import Prisma from "../providers/Prisma"; Interaction,
import osuAPI from "../providers/osuAPI"; CommandInteraction
import { countryCodeEmoji } from "country-code-emoji"; } from 'discord.js';
import countryLookup from "country-code-lookup";
import validator from 'validator'; 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 = { const EMBEDS = {
osu_INFO:(data: Message | Interaction) => { osu_INFO: (data: Message | Interaction) => {
return makeInfoEmbed ({ return makeInfoEmbed({
title: 'osu!', 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`, description: `[osu!](https://osu.ppy.sh/home) is a free-to-play rhythm game primarily developed, published, and created by Dean "peppy" Herbert`,
fields: [ fields: [
@@ -23,52 +34,51 @@ const EMBEDS = {
value: '``user``' value: '``user``'
} }
], ],
user: (data instanceof Interaction) ? data.user : data.author user: data instanceof Interaction ? data.user : data.author
}); });
}, },
NO_USER_FOUND: (data: Message | Interaction) => { NO_USER_FOUND: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: `That user doesn't exists on osu!`, 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) => { NO_USER_MENTIONED: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: `No osu! username or user id provided`, 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) => { INVALID_USER_MENTIONED: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: `Not a valid osu username or id`, 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) => { INVALID_BEATMAP_ID_MENTIONED: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: `Not a valid osu beatmap id`, 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) => { NO_BEATMAP_FOUND: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: `That beatmap doesn't exists on osu!`, 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) => { NO_BEATMAP_MENTIONED: (data: Message | Interaction) => {
return makeErrorEmbed ({ return makeErrorEmbed({
title: `No osu! beatmap id provided`, 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 { export default class osu extends DiscordModule {
public id = 'Discord_osu';
public id = "Discord_osu"; public commands = ['osu'];
public commands = ["osu"]; public commandInteractionName = 'osu';
public commandInteractionName = "osu";
async GuildOnModuleCommand(args: any, message: Message) { async GuildOnModuleCommand(args: any, message: Message) {
await this.run(new HybridInteractionMessage(message), args); await this.run(new HybridInteractionMessage(message), args);
@@ -79,116 +89,156 @@ export default class osu extends DiscordModule {
} }
async run(data: HybridInteractionMessage, args: any) { async run(data: HybridInteractionMessage, args: any) {
const Guild = await Prisma.client.guild.findFirst({ where: { id: data.getGuild()!.id } });
const Guild = await Prisma.client.guild.findFirst({ where: { id: data.getGuild()!.id }}) if (!Guild) return;
if(!Guild) return;
const funct = { const funct = {
user: async(data: HybridInteractionMessage) => { user: async (data: HybridInteractionMessage) => {
let user; let user;
if(data.isMessage()) { if (data.isMessage()) {
if(typeof args[1] === 'undefined') if (typeof args[1] === 'undefined')
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_USER_MENTIONED(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.NO_USER_MENTIONED(data.getRaw())]
});
const [removed, ...newArgs] = args; const [removed, ...newArgs] = args;
user = newArgs.join(" "); user = newArgs.join(' ');
} } else if (data.isSlashCommand())
else if(data.isSlashCommand())
user = data.getSlashCommand().options.getString('user'); user = data.getSlashCommand().options.getString('user');
if (!validator.isNumeric(user) && !this.validate_osu_username(user))
if(!validator.isNumeric(user) && !this.validate_osu_username(user)) return await sendHybridInteractionMessageResponse(data, {
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_USER_MENTIONED(data.getRaw())] }); embeds: [EMBEDS.INVALID_USER_MENTIONED(data.getRaw())]
});
let result = await osuAPI.client.getUser({ u: user }); let result = await osuAPI.client.getUser({ u: user });
if(result instanceof Array && result.length === 0) if (result instanceof Array && result.length === 0)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_USER_FOUND(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.NO_USER_FOUND(data.getRaw())]
});
if(data.isSlashCommand()) { if (data.isSlashCommand()) {
await data.getSlashCommand().deferReply(); await data.getSlashCommand().deferReply();
} }
const level = { const level = {
number: (Math.round((result.level + Number.EPSILON) * 100) / 100).toFixed(2).split('.')[0], number: (Math.round((result.level + Number.EPSILON) * 100) / 100)
progression: (Math.round((result.level + Number.EPSILON) * 100) / 100).toFixed(2).split('.')[1] .toFixed(2)
} .split('.')[0],
const embed = makeInfoEmbed ({ progression: (Math.round((result.level + Number.EPSILON) * 100) / 100)
.toFixed(2)
.split('.')[1]
};
const embed = makeInfoEmbed({
icon: '', icon: '',
title: `${countryCodeEmoji(result.country)} ${result.name}`, title: `${countryCodeEmoji(result.country)} ${result.name}`,
//description: `${member.user.username}#${member.user.discriminator} (${member.user.id})`, //description: `${member.user.username}#${member.user.discriminator} (${member.user.id})`,
fields: [ fields: [
{ {
name: `🏆 Level **${level.number}** (${level.progression}% progress to the next level)`, 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 value: `Play Count **${this.numberWithCommas(
\u200b`, 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)}**`, value: `**#${this.numberWithCommas(result.pp.rank)}**`,
inline: true inline: true
}, },
{ {
name: `${countryCodeEmoji(result.country)} Country Ranking`, 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 inline: true
}, },
{ {
name: "🎀 Total Score", name: '🎀 Total Score',
value: `**${this.numberWithCommas(result.scores.total)}**`, value: `**${this.numberWithCommas(result.scores.total)}**`,
inline: true inline: true
}, },
{ {
name: "✨ PP", name: '✨ PP',
value: `**${this.numberWithCommas(result.pp.raw)}pp**`, value: `**${this.numberWithCommas(result.pp.raw)}pp**`,
inline: true inline: true
}, },
{ {
name: "⭕ Hit Accuracy", name: '⭕ Hit Accuracy',
value: `**${result.accuracyFormatted}**`, value: `**${result.accuracyFormatted}**`,
inline: true inline: true
}, },
{ {
name: "🌠 Ranked Score", name: '🌠 Ranked Score',
value: `**${this.numberWithCommas(result.scores.ranked)}** value: `**${this.numberWithCommas(result.scores.ranked)}**
\u200b`, \u200b`,
inline: true inline: true
}, },
{ {
name: "🥇 SSH", name: '🥇 SSH',
value: `**${this.numberWithCommas(result.counts.SSH)}**`, value: `**${this.numberWithCommas(result.counts.SSH)}**`,
inline: true inline: true
}, },
{ {
name: "🥇 SH", name: '🥇 SH',
value: `**${this.numberWithCommas(result.counts.SH)}**`, value: `**${this.numberWithCommas(result.counts.SH)}**`,
inline: true inline: true
}, },
{ {
name: "🥇 SS", name: '🥇 SS',
value: `**${this.numberWithCommas(result.counts.SS)}**`, value: `**${this.numberWithCommas(result.counts.SS)}**`,
inline: true inline: true
}, },
{ {
name: "🥈 S", name: '🥈 S',
value: `**${this.numberWithCommas(result.counts.S)}**`, value: `**${this.numberWithCommas(result.counts.S)}**`,
inline: true inline: true
}, },
{ {
name: "🥉 A", name: '🥉 A',
value: `**${this.numberWithCommas(result.counts.A)}**`, value: `**${this.numberWithCommas(result.counts.A)}**`,
inline: true inline: true
}, },
{ {
name: "🏅 > A / Total plays", 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)}) 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`, \u200b`,
inline: true inline: true
}, },
{ {
name: `❤ Account Information`, name: `❤ Account Information`,
value: `Joined: <t:${Math.round(new Date(result.raw_joinDate).getTime() / 1000)}:R>, <t:${Math.round(new Date(result.raw_joinDate).getTime() / 1000)}:f>` value: `Joined: <t:${Math.round(
}//, new Date(result.raw_joinDate).getTime() / 1000
)}:R>, <t:${Math.round(
new Date(result.raw_joinDate).getTime() / 1000
)}:f>`
} //,
/*{ /*{
name: `💌 Recent Events (Coming soon)`, name: `💌 Recent Events (Coming soon)`,
value: `*How about we explore the area ahead of us later?*` value: `*How about we explore the area ahead of us later?*`
@@ -203,102 +253,110 @@ export default class osu extends DiscordModule {
}); });
// TODO: Fix for ppl with no image // 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() const row = new MessageActionRow().addComponents(
.addComponents(
new MessageButton() new MessageButton()
.setEmoji('🔗') .setEmoji('🔗')
.setLabel(' Open Profile') .setLabel(' Open Profile')
.setURL(`https://osu.ppy.sh/users/${result.id}`) .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; let beatmap;
if(data.isMessage()) { if (data.isMessage()) {
if(typeof args[1] === 'undefined') if (typeof args[1] === 'undefined')
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_BEATMAP_MENTIONED(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.NO_BEATMAP_MENTIONED(data.getRaw())]
});
const [removed, ...newArgs] = args; const [removed, ...newArgs] = args;
beatmap = newArgs.join(" "); beatmap = newArgs.join(' ');
} } else if (data.isSlashCommand())
else if(data.isSlashCommand())
beatmap = data.getSlashCommand().options.getString('beatmap'); beatmap = data.getSlashCommand().options.getString('beatmap');
if (!validator.isNumeric(beatmap))
if(!validator.isNumeric(beatmap)) return await sendHybridInteractionMessageResponse(data, {
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.INVALID_BEATMAP_ID_MENTIONED(data.getRaw())] }); embeds: [EMBEDS.INVALID_BEATMAP_ID_MENTIONED(data.getRaw())]
});
let result = await osuAPI.client.getBeatmaps({ b: beatmap }); let result = await osuAPI.client.getBeatmaps({ b: beatmap });
if(result instanceof Array && result.length === 0) if (result instanceof Array && result.length === 0)
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.NO_BEATMAP_FOUND(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.NO_BEATMAP_FOUND(data.getRaw())]
});
if(data.isSlashCommand()) if (data.isSlashCommand()) await data.getSlashCommand().deferReply();
await data.getSlashCommand().deferReply();
const bm_result = result[0]; const bm_result = result[0];
let url_mode = "#osu"; let url_mode = '#osu';
let statusEmoji = "⚪"; let statusEmoji = '⚪';
let mode: unknown = bm_result.mode; let mode: unknown = bm_result.mode;
let status: unknown = bm_result.approvalStatus; let status: unknown = bm_result.approvalStatus;
if((mode as String) === "Taiko") if ((mode as String) === 'Taiko') url_mode = '#taiko';
url_mode = "#taiko"; else if ((mode as String) === 'Catch the Beat') url_mode = '#fruits';
else if((mode as String) === "Catch the Beat") else if ((mode as String) === 'Mania') url_mode = '#mania';
url_mode = "#fruits";
else if((mode as String) === "Mania")
url_mode = "#mania";
if((status as String) === "Ranked") if ((status as String) === 'Ranked') statusEmoji = '🏆';
statusEmoji = "🏆"; else if ((status as String) === 'Loved') statusEmoji = '❤';
else if((status as String) === "Loved") else if ((status as String) === 'Qualified') statusEmoji = '✅';
statusEmoji = "❤"; else if ((status as String) === 'WIP') statusEmoji = '🛠';
else if((status as String) === "Qualified") else if ((status as String) === 'Pending') statusEmoji = '⌛';
statusEmoji = "✅"; else if ((status as String) === 'Graveyard') 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: '', icon: '',
title: `${bm_result.title} - ${bm_result.artist}`, title: `${bm_result.title} - ${bm_result.artist}`,
fields: [ fields: [
{ {
name: `Difficulty **[${bm_result.version}]**`, 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** Rating **${bm_result.rating.toFixed(2)}/10**
\u200b`, \u200b`
}, },
{ {
name: "⭐ Star Difficulty", name: '⭐ Star Difficulty',
value: `**${(Math.round((bm_result.difficulty.rating + Number.EPSILON) * 100) / 100).toFixed(2)}**`, value: `**${(
Math.round((bm_result.difficulty.rating + Number.EPSILON) * 100) /
100
).toFixed(2)}**`,
inline: true inline: true
}, },
{ {
name: `⌛ Length`, 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 inline: true
}, },
{ {
name: "🏓 Combo", name: '🏓 Combo',
value: `**${this.numberWithCommas(bm_result.maxCombo)}**`, value: `**${this.numberWithCommas(bm_result.maxCombo)}**`,
inline: true inline: true
}, },
{ {
name: "🕹 Mode", name: '🕹 Mode',
value: `**${mode}**`, value: `**${mode}**`,
inline: true inline: true
}, },
{ {
name: "🎵 BPM", name: '🎵 BPM',
value: `**${bm_result.bpm}**`, value: `**${bm_result.bpm}**`,
inline: true inline: true
}, },
@@ -309,17 +367,17 @@ export default class osu extends DiscordModule {
inline: true inline: true
}, },
{ {
name: "⭕ Circle", name: '⭕ Circle',
value: `**${bm_result.objects.normal}**`, value: `**${bm_result.objects.normal}**`,
inline: true inline: true
}, },
{ {
name: "💨 Slider", name: '💨 Slider',
value: `**${bm_result.objects.slider}**`, value: `**${bm_result.objects.slider}**`,
inline: true inline: true
}, },
{ {
name: "💫 Spinner", name: '💫 Spinner',
value: `**${bm_result.objects.spinner}** value: `**${bm_result.objects.spinner}**
\u200b`, \u200b`,
inline: true inline: true
@@ -328,30 +386,42 @@ export default class osu extends DiscordModule {
name: `🎶 Track Information`, name: `🎶 Track Information`,
value: `Language: **${bm_result.language}** value: `Language: **${bm_result.language}**
Genre: **${bm_result.genre}** Genre: **${bm_result.genre}**
Submission Date: <t:${Math.round(new Date(bm_result.raw_submitDate).getTime() / 1000)}:R>, <t:${Math.round(new Date(bm_result.raw_submitDate).getTime() / 1000)}:f> Submission Date: <t:${Math.round(
Last updated: <t:${Math.round(new Date(bm_result.raw_lastUpdate).getTime() / 1000)}:R>, <t:${Math.round(new Date(bm_result.raw_lastUpdate).getTime() / 1000)}:f> new Date(bm_result.raw_submitDate).getTime() / 1000
Approved: <t:${Math.round(new Date(bm_result.raw_approvedDate).getTime() / 1000)}:R>, <t:${Math.round(new Date(bm_result.raw_approvedDate).getTime() / 1000)}:f> )}:R>, <t:${Math.round(
\u200b`, new Date(bm_result.raw_submitDate).getTime() / 1000
)}:f>
Last updated: <t:${Math.round(
new Date(bm_result.raw_lastUpdate).getTime() / 1000
)}:R>, <t:${Math.round(
new Date(bm_result.raw_lastUpdate).getTime() / 1000
)}:f>
Approved: <t:${Math.round(
new Date(bm_result.raw_approvedDate).getTime() / 1000
)}:R>, <t:${Math.round(
new Date(bm_result.raw_approvedDate).getTime() / 1000
)}:f>
\u200b`
}, },
{ {
name: "▶ Plays", name: '▶ Plays',
value: `**${this.numberWithCommas(bm_result.counts.plays)}**`, value: `**${this.numberWithCommas(bm_result.counts.plays)}**`,
inline: true inline: true
}, },
{ {
name: "🏁 Passes", name: '🏁 Passes',
value: `**${this.numberWithCommas(bm_result.counts.passes)}**`, value: `**${this.numberWithCommas(bm_result.counts.passes)}**`,
inline: true inline: true
}, },
{ {
name: "♥ Favorites", name: '♥ Favorites',
value: `**${this.numberWithCommas(bm_result.counts.favorites)}** value: `**${this.numberWithCommas(bm_result.counts.favorites)}**
\u200b`, \u200b`,
inline: true inline: true
}, },
{ {
name: `📌 Tags`, name: `📌 Tags`,
value: `\`\`${bm_result.tags.join(" ")}\`\``, value: `\`\`${bm_result.tags.join(' ')}\`\``
} }
], ],
user: data.getUser() 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}`, 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` 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(); const row = new MessageActionRow();
if(bm_result.hasDownload) if (bm_result.hasDownload)
row.addComponents( row.addComponents(
new MessageButton() new MessageButton()
.setEmoji('🌎') .setEmoji('🌎')
.setLabel(' Download (Beatconnect)') .setLabel(' Download (Beatconnect)')
.setURL(`https://beatconnect.io/b/${bm_result.beatmapSetId}/`) .setURL(`https://beatconnect.io/b/${bm_result.beatmapSetId}/`)
.setStyle('LINK'), .setStyle('LINK')
) );
row.addComponents( row.addComponents(
new MessageButton() new MessageButton()
.setEmoji('🔗') .setEmoji('🔗')
.setLabel(' Open listing') .setLabel(' Open listing')
.setURL(`https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}${url_mode}/${bm_result.id}`) .setURL(
.setStyle('LINK'), `https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}${url_mode}/${bm_result.id}`
) )
.setStyle('LINK')
);
row.addComponents( row.addComponents(
new MessageButton() new MessageButton()
.setEmoji('💬') .setEmoji('💬')
.setLabel(' Open discussion') .setLabel(' Open discussion')
.setURL(`https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}/discussion`) .setURL(
.setStyle('LINK'), `https://osu.ppy.sh/beatmapsets/${bm_result.beatmapSetId}/discussion`
) )
.setStyle('LINK')
);
return await sendHybridInteractionMessageResponse(data, { embeds: [embed2], components: [row] }); return await sendHybridInteractionMessageResponse(data, {
} embeds: [embed2],
components: [row]
});
} }
};
let query; let query;
if(data.isMessage()) { if (data.isMessage()) {
if(args.length === 0) { if (args.length === 0) {
return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.osu_INFO(data.getRaw())] }); return await sendHybridInteractionMessageResponse(data, {
embeds: [EMBEDS.osu_INFO(data.getRaw())]
});
} }
query = args[0].toLowerCase(); query = args[0].toLowerCase();
} } else if (data.isSlashCommand()) {
else if(data.isSlashCommand()) {
query = args.getSubcommand(); query = args.getSubcommand();
} }
switch(query) { switch (query) {
case "user": case 'user':
case "u": case 'u':
return await funct.user(data); return await funct.user(data);
case "beatmap": case 'beatmap':
case "b": case 'b':
return await funct.beatmap(data); return await funct.beatmap(data);
} }
} }
private numberWithCommas(x: Number) { private numberWithCommas(x: Number) {
try { try {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
} catch(err) { } catch (err) {
return x; return x;
} }
} }
// Criteria from https://github.com/ppy/osu-web/blob/9de00a0b874c56893d98261d558d78d76259d81b/app/Libraries/UsernameValidation.php // Criteria from https://github.com/ppy/osu-web/blob/9de00a0b874c56893d98261d558d78d76259d81b/app/Libraries/UsernameValidation.php
private validate_osu_username(username: string) { private validate_osu_username(username: string) {
//username_no_spaces //username_no_spaces
if (username.startsWith(' ') || username.endsWith(' ')) return false; if (username.startsWith(' ') || username.endsWith(' ')) return false;
@@ -436,12 +514,11 @@ export default class osu extends DiscordModule {
if (username.length > 15) return false; if (username.length > 15) return false;
//username_invalid_characters //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 //username_no_space_userscore_mix
if (username.includes('_') && username.includes(' ')) return false; if (username.includes('_') && username.includes(' ')) return false;
return true; return true;
} }
} }
+5 -11
View File
@@ -1,19 +1,13 @@
import { CustomError } from 'ts-custom-error' import { CustomError } from 'ts-custom-error';
export class ServiceError extends CustomError { export class ServiceError extends CustomError {
public constructor( public constructor(public statusCode: number, message: string) {
public statusCode: number, super(message);
message: string
) {
super(message)
} }
} }
export class DatabaseError extends CustomError { export class DatabaseError extends CustomError {
public constructor( public constructor(message: string) {
message: string super(message);
) {
super(message)
} }
} }
+4 -9
View File
@@ -1,12 +1,8 @@
import Logger from '../libs/Logger'; import Logger from '../libs/Logger';
import App from '../providers/App';
class NativeException { class NativeException {
public process(): void {
public process (): void { process.on('uncaughtException', (exception) => {
process.on('uncaughtException', exception => {
Logger.log('critical', 'Critical error, cleaning up and exiting'); Logger.log('critical', 'Critical error, cleaning up and exiting');
Logger.log('critical', exception.stack); Logger.log('critical', exception.stack);
@@ -14,11 +10,10 @@ class NativeException {
process.exit(1); process.exit(1);
}); });
process.on('unhandledRejection', exception => { process.on('unhandledRejection', (exception) => {
throw exception; throw exception;
}); });
} }
} }
export default new NativeException; export default new NativeException();
+6 -8
View File
@@ -7,7 +7,7 @@ const levels = {
warn: 3, warn: 3,
info: 4, info: 4,
http: 5, http: 5,
debug: 6, debug: 6
}; };
const level = () => { const level = () => {
@@ -23,7 +23,7 @@ const colors = {
warn: 'yellow', warn: 'yellow',
info: 'green', info: 'green',
http: 'magenta', http: 'magenta',
debug: 'white', debug: 'white'
}; };
winston.addColors(colors); winston.addColors(colors);
@@ -31,25 +31,23 @@ winston.addColors(colors);
const format = winston.format.combine( const format = winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }), winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }),
winston.format.colorize({ all: true }), winston.format.colorize({ all: true }),
winston.format.printf( winston.format.printf((info) => `[${info.timestamp}] [${info.level}] ${info.message}`)
(info) => `[${info.timestamp}] [${info.level}] ${info.message}`
)
); );
const transports = [ const transports = [
new winston.transports.Console(), new winston.transports.Console(),
new winston.transports.File({ new winston.transports.File({
filename: 'logs/error.log', 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({ const Logger = winston.createLogger({
level: level(), level: level(),
levels, levels,
format, format,
transports, transports
}); });
export default Logger; export default Logger;
+6 -6
View File
@@ -1,15 +1,15 @@
import Logger from '../libs/Logger';
import Environment from './Environment'; import Environment from './Environment';
import Configuration from './Configuration';
import Prisma from './Prisma'; import Prisma from './Prisma';
import Discord from './Discord'; import Discord from './Discord';
import osu from './osuAPI'; import osu from './osuAPI';
import Configuration from './Configuration';
import Logger from '../libs/Logger';
class App { class App {
public readonly versionNumber = `0.09`; 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 { public loadConfig(): void {
Logger.log('info', 'Loading configuration'); Logger.log('info', 'Loading configuration');
@@ -37,4 +37,4 @@ class App {
} }
} }
export default new App; export default new App();
+11 -18
View File
@@ -1,30 +1,27 @@
import { Guild } from "@prisma/client"; import { Guild } from '@prisma/client';
import { Snowflake } from "discord-api-types/v10"; import { Snowflake } from 'discord-api-types/v10';
import Prisma from "./Prisma"; import Prisma from './Prisma';
class Cache { class Cache {
private cache: any; private cache: any;
constructor () { constructor() {
this.cache = { this.cache = {
Guilds: { Guilds: {}
}
}; };
} }
public async updateGuildsCache() { public async updateGuildsCache() {
const Guilds = await Prisma.client.guild.findMany(); const Guilds = await Prisma.client.guild.findMany();
for(let Guild of Guilds) { for (let Guild of Guilds) {
this.setGuildData(Guild.id, Guild); this.setGuildData(Guild.id, Guild);
} }
} }
public async updateGuildCache(guildID: Snowflake) { public async updateGuildCache(guildID: Snowflake) {
const DBGuild = await Prisma.client.guild.findFirst({ where:{id: guildID} }); const DBGuild = await Prisma.client.guild.findFirst({ where: { id: guildID } });
if(DBGuild === null) return; if (DBGuild === null) return;
this.setGuildData(guildID, DBGuild); this.setGuildData(guildID, DBGuild);
} }
@@ -32,9 +29,8 @@ class Cache {
this.cache.Guilds[id] = data; this.cache.Guilds[id] = data;
} }
public async getGuild(id: string): Promise<(Guild | undefined)> { public async getGuild(id: string): Promise<Guild | undefined> {
if(typeof this.cache.Guilds[id] !== 'undefined') if (typeof this.cache.Guilds[id] !== 'undefined') return this.cache.Guilds[id];
return this.cache.Guilds[id];
const Guild = await Prisma.client.guild.findFirst({ const Guild = await Prisma.client.guild.findFirst({
where: { where: {
@@ -42,18 +38,15 @@ class Cache {
} }
}); });
if(Guild === null) if (Guild === null) return undefined;
return undefined;
this.setGuildData(Guild.id, Guild); this.setGuildData(Guild.id, Guild);
return this.cache.Guilds[id]; return this.cache.Guilds[id];
} }
public getGuilds(): void { public getGuilds(): void {
return this.cache.Guilds; return this.cache.Guilds;
} }
} }
export default new Cache(); export default new Cache();
+18 -16
View File
@@ -1,19 +1,18 @@
import fs from "fs"; import fs from 'fs';
import path from "path"; import path from 'path';
const ConfigurationData: any = []; const ConfigurationData: any = [];
class Configuration { class Configuration {
public init(): void { public init(): void {
const dir = path.join(process.cwd(), 'configs/'); const dir = path.join(process.cwd(), 'configs/');
if (!fs.existsSync(dir)) { if (!fs.existsSync(dir)) {
fs.mkdirSync(dir); fs.mkdirSync(dir);
} }
this.copyExampleIfNotExists("Ping.json"); this.copyExampleIfNotExists('Ping.json');
this.copyExampleIfNotExists("ServiceAnnouncement.json"); this.copyExampleIfNotExists('ServiceAnnouncement.json');
this.loadConfig("Ping.json"); this.loadConfig('Ping.json');
this.loadConfig("ServiceAnnouncement.json"); this.loadConfig('ServiceAnnouncement.json');
} }
public loadConfig(configFileName: string): void { public loadConfig(configFileName: string): void {
@@ -22,27 +21,30 @@ class Configuration {
throw new Error(`Config file ${configFileName} does not exist`); throw new Error(`Config file ${configFileName} does not exist`);
const config = JSON.parse(fs.readFileSync(path.join(dir, configFileName)).toString()); const config = JSON.parse(fs.readFileSync(path.join(dir, configFileName)).toString());
ConfigurationData[configFileName.replace(/\.[^/.]+$/, "")] = config; ConfigurationData[configFileName.replace(/\.[^/.]+$/, '')] = config;
} }
public getConfig(key?: string) { public getConfig(key?: string) {
if(!key) if (!key) return ConfigurationData;
return ConfigurationData;
else { else {
if(ConfigurationData[key]) if (ConfigurationData[key]) return ConfigurationData[key];
return ConfigurationData[key]; else throw new Error(`No configuration found for ${key}`);
else
throw new Error(`No configuration found for ${key}`);
} }
} }
private copyExampleIfNotExists(file: string): void { private copyExampleIfNotExists(file: string): void {
const dir = path.join(process.cwd(), 'configs/'); const dir = path.join(process.cwd(), 'configs/');
if (!fs.existsSync(path.join(dir, file))) { 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(); export default new Configuration();
+153 -115
View File
@@ -1,53 +1,56 @@
import { Guild, Client, GuildMember, Intents, Interaction, Message, TextChannel} from "discord.js"; import { Guild, Client, GuildMember, Intents, Interaction, Message, TextChannel } from 'discord.js';
import { Guild as GuildPrisma } from ".prisma/client";
import Logger from "../libs/Logger"; import Logger from '../libs/Logger';
import Environment from "./Environment"; import Environment from './Environment';
import Discord_Core from "../discord/Core"; import Discord_Core from '../discord/Core';
import Discord_Settings from "../discord/Settings"; import Discord_Settings from '../discord/Settings';
import Discord_Ping from "../discord/Ping"; import Discord_Ping from '../discord/Ping';
import Discord_Help from "../discord/Help"; import Discord_Help from '../discord/Help';
import Discord_Invite from "../discord/Invite"; import Discord_Invite from '../discord/Invite';
import Discord_Say from "../discord/Say"; import Discord_Say from '../discord/Say';
import Discord_InteractionManager from "../discord/InteractionManager"; import Discord_InteractionManager from '../discord/InteractionManager';
import Discord_MembershipScreening from "../discord/MembershipScreening"; import Discord_MembershipScreening from '../discord/MembershipScreening';
import Discord_osu from "../discord/osu"; import Discord_osu from '../discord/osu';
import Discord_UserInfo from "../discord/UserInfo"; import Discord_UserInfo from '../discord/UserInfo';
import Discord_Stats from "../discord/Stats"; import Discord_Stats from '../discord/Stats';
import Discord_MusicPlayer_Play from "../discord/MusicPlayer/Play"; import Discord_MusicPlayer_Play from '../discord/MusicPlayer/Play';
import Discord_MusicPlayer_Skip from "../discord/MusicPlayer/Skip"; import Discord_MusicPlayer_Skip from '../discord/MusicPlayer/Skip';
import Discord_MusicPlayer_Join from "../discord/MusicPlayer/Join"; import Discord_MusicPlayer_Join from '../discord/MusicPlayer/Join';
import Discord_MusicPlayer_Leave from "../discord/MusicPlayer/Leave"; import Discord_MusicPlayer_Leave from '../discord/MusicPlayer/Leave';
import Discord_MusicPlayer_Queue from "../discord/MusicPlayer/Queue"; import Discord_MusicPlayer_Queue from '../discord/MusicPlayer/Queue';
import Discord_MusicPlayer_Search from "../discord/MusicPlayer/Search"; import Discord_MusicPlayer_Search from '../discord/MusicPlayer/Search';
import Discord_MusicPlayer_NowPlaying from "../discord/MusicPlayer/NowPlaying"; import Discord_MusicPlayer_NowPlaying from '../discord/MusicPlayer/NowPlaying';
import Discord_MusicPlayer_Loop from "../discord/MusicPlayer/Loop"; import Discord_MusicPlayer_Loop from '../discord/MusicPlayer/Loop';
import Discord_MusicPlayer_Pause from "../discord/MusicPlayer/Pause"; import Discord_MusicPlayer_Pause from '../discord/MusicPlayer/Pause';
import Discord_MusicPlayer_Resume from "../discord/MusicPlayer/Resume"; import Discord_MusicPlayer_Resume from '../discord/MusicPlayer/Resume';
import Discord_Developer_ServiceAnnouncement from "../discord/developer/ServiceAnnouncement"; import Discord_Developer_ServiceAnnouncement from '../discord/developer/ServiceAnnouncement';
import Discord_Developer_Debug from "../discord/developer/Debug"; import Discord_Developer_Debug from '../discord/developer/Debug';
import Cache from "./Cache"; import Cache from './Cache';
import DiscordModule from "../utils/DiscordModule"; import DiscordModule from '../utils/DiscordModule';
import { Map } from "typescript"; import { Map } from 'typescript';
class Discord { class Discord {
public client: Client; public client: Client;
private loaded_module = new Map<string, DiscordModule>(); private loaded_module = new Map<string, DiscordModule>();
constructor () { constructor() {
this.client = new Client({ this.client = new Client({
//partials: ['MESSAGE', 'CHANNEL', 'REACTION'], //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 { public init(): void {
Logger.info('Logging in to discord'); Logger.info('Logging in to discord');
this.client.login(Environment.get().DISCORD_TOKEN); this.client.login(Environment.get().DISCORD_TOKEN);
@@ -80,57 +83,68 @@ class Discord {
new Discord_Developer_Debug() new Discord_Developer_Debug()
]; ];
for(const _module of modules) { for (const _module of modules) {
if(_module.id) { if (_module.id) {
if(this.loaded_module.has(_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.`); Logger.error(
else `Module ${
this.loaded_module.set(_module.id, _module); _module.constructor.name
} } is trying to assign a conflicting module id ${_module.id}. ${
else this.loaded_module.get(_module.id)!.constructor.name
Logger.error(`Invalid module ${_module.constructor.name}. The module does not have an id.`); } 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`); 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]; let thisModule: DiscordModule = module[1];
thisModule.Init(); thisModule.Init();
} }
// On bot logged in // On bot logged in
this.client.on("ready", () => { this.client.on('ready', () => {
for(const module of this.loaded_module) { for (const module of this.loaded_module) {
let thisModule: DiscordModule = module[1]; let thisModule: DiscordModule = module[1];
thisModule.Ready(); thisModule.Ready();
} }
}); });
// Member join guild event to modules // Member join guild event to modules
this.client.on("guildMemberAdd", (member: GuildMember) => { this.client.on('guildMemberAdd', (member: GuildMember) => {
for(const module of this.loaded_module) { for (const module of this.loaded_module) {
let thisModule: DiscordModule = module[1]; let thisModule: DiscordModule = module[1];
thisModule.GuildMemberAdd(member); thisModule.GuildMemberAdd(member);
} }
}); });
// Interaction create event to modules // Interaction create event to modules
this.client.on("interactionCreate", (interaction: Interaction) => { this.client.on('interactionCreate', (interaction: Interaction) => {
for(const module of this.loaded_module) { for (const module of this.loaded_module) {
let thisModule: DiscordModule = module[1]; let thisModule: DiscordModule = module[1];
if(interaction.guild) { if (interaction.guild) {
thisModule.GuildInteractionCreate(interaction); thisModule.GuildInteractionCreate(interaction);
if(interaction.isCommand() && interaction.commandName && thisModule.commandInteractionName) { if (
interaction.isCommand() &&
interaction.commandName &&
thisModule.commandInteractionName
) {
thisModule.GuildCommandInteractionCreate(interaction); thisModule.GuildCommandInteractionCreate(interaction);
if(interaction.commandName.toLowerCase() === thisModule.commandInteractionName) if (
interaction.commandName.toLowerCase() ===
thisModule.commandInteractionName
)
thisModule.GuildModuleCommandInteractionCreate(interaction); thisModule.GuildModuleCommandInteractionCreate(interaction);
} } else if (interaction.isButton()) {
else if(interaction.isButton()) {
thisModule.GuildButtonInteractionCreate(interaction); thisModule.GuildButtonInteractionCreate(interaction);
} } else if (interaction.isSelectMenu()) {
else if(interaction.isSelectMenu()) {
thisModule.GuildSelectMenuInteractionCreate(interaction); thisModule.GuildSelectMenuInteractionCreate(interaction);
} }
} }
@@ -140,71 +154,100 @@ class Discord {
}); });
// Message create event to modules // Message create event to modules
this.client.on("messageCreate", (message: Message) => { this.client.on('messageCreate', (message: Message) => {
for(const module of this.loaded_module) { for (const module of this.loaded_module) {
let thisModule: DiscordModule = module[1]; let thisModule: DiscordModule = module[1];
thisModule.GuildMessageCreate(message); thisModule.GuildMessageCreate(message);
} }
}); });
// Joined guild event to modules // Joined guild event to modules
this.client.on("guildCreate", (guild: Guild) => { this.client.on('guildCreate', (guild: Guild) => {
for(const module of this.loaded_module) { for (const module of this.loaded_module) {
let thisModule: DiscordModule = module[1]; let thisModule: DiscordModule = module[1];
thisModule.GuildCreate(guild); thisModule.GuildCreate(guild);
} }
}); });
// Handling guild commands // Handling guild commands
this.client.on("messageCreate", async (message: Message) => { this.client.on('messageCreate', async (message: Message) => {
if (!(message.channel instanceof TextChannel)) return;
if(!(message.channel instanceof TextChannel)) return; if (message.author.bot) return;
if(message.author.bot) return; if (typeof message.guild?.id === 'undefined') return;
if(typeof message.guild?.id === 'undefined') return;
let GuildCache = await Cache.getGuild(message.guild.id); 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 noPrefixMessage = message.content.replace(GuildCache.prefix, '');
let symbols = [ let symbols = [
'!','@','#','$','%','^','&','*','(',')','-','=','_','+','\\','/','<','>','[',']','{','}','`','"',"'",',','.','~','|',';',':','?','、','。' '!',
'@',
'#',
'$',
'%',
'^',
'&',
'*',
'(',
')',
'-',
'=',
'_',
'+',
'\\',
'/',
'<',
'>',
'[',
']',
'{',
'}',
'`',
'"',
"'",
',',
'.',
'~',
'|',
';',
':',
'?',
'、',
'。'
]; ];
const isTag = (prefix: string) => { const isTag = (prefix: string) => {
return prefix.startsWith('<@!') && prefix.endsWith('>') || return (
prefix.startsWith('<:') && prefix.endsWith('>') || (prefix.startsWith('<@!') && prefix.endsWith('>')) ||
prefix.startsWith('<a:') && prefix.endsWith('>') || (prefix.startsWith('<:') && prefix.endsWith('>')) ||
prefix.startsWith('<#') && prefix.endsWith('>'); (prefix.startsWith('<a:') && prefix.endsWith('>')) ||
} (prefix.startsWith('<#') && prefix.endsWith('>'))
);
};
if((GuildCache.prefix.indexOf(' ') >= 0)) { if (GuildCache.prefix.indexOf(' ') >= 0) {
if(noPrefixMessage.charAt(0) !== ' ') return; if (noPrefixMessage.charAt(0) !== ' ') return;
} } else {
else { if (symbols.includes(GuildCache.prefix.charAt(GuildCache.prefix.length - 1))) {
if(symbols.includes(GuildCache.prefix.charAt(GuildCache.prefix.length - 1))) { if (noPrefixMessage.charAt(0) === ' ') {
if(noPrefixMessage.charAt(0) === ' ') {
//Handle for "@Bot <command>" //Handle for "@Bot <command>"
if(isTag(GuildCache.prefix)) {} if (isTag(GuildCache.prefix)) {
else } else return;
return; } else {
}
else {
//Handle for "@Bot<command>" //Handle for "@Bot<command>"
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.charAt(0) !== ' ' && !symbols.includes(noPrefixMessage.charAt(0))) return;
} }
if(noPrefixMessage === '') return; if (noPrefixMessage === '') return;
if(noPrefixMessage.charAt(0) === ' ') { if (noPrefixMessage.charAt(0) === ' ') {
/*if(symbols.includes(GuildCache.prefix.charAt(GuildCache.prefix.length - 1))) { /*if(symbols.includes(GuildCache.prefix.charAt(GuildCache.prefix.length - 1))) {
if((GuildCache.prefix.indexOf(' ') >= 0)) return; if((GuildCache.prefix.indexOf(' ') >= 0)) return;
}*/ }*/
@@ -212,59 +255,54 @@ class Discord {
noPrefixMessage = noPrefixMessage.substring(1); noPrefixMessage = noPrefixMessage.substring(1);
} }
let args = noPrefixMessage.split(" "); let args = noPrefixMessage.split(' ');
args = args.filter(e => e !== ''); args = args.filter((e) => e !== '');
let command = args[0]; let command = args[0];
args.shift(); args.shift();
if(args.length === 0) if (args.length === 0) args = [];
args = [];
for(const module of this.loaded_module) { for (const module of this.loaded_module) {
let thisModule: DiscordModule = module[1]; let thisModule: DiscordModule = module[1];
thisModule.GuildOnCommand(command, args, message); thisModule.GuildOnCommand(command, args, message);
if(thisModule.commands && thisModule.commands.includes(command)) if (thisModule.commands && thisModule.commands.includes(command))
thisModule.GuildOnModuleCommand(args, message); thisModule.GuildOnModuleCommand(args, message);
} }
}); });
// Handling mentions // Handling mentions
this.client.on("messageCreate", async (message: Message) => { this.client.on('messageCreate', async (message: Message) => {
// TODO: Handle DMs commands soon // TODO: Handle DMs commands soon
if(!(message.channel instanceof TextChannel)) return; if (!(message.channel instanceof TextChannel)) return;
if(message.author.bot) return; if (message.author.bot) return;
if(typeof message.guild?.id === 'undefined') return; if (typeof message.guild?.id === 'undefined') return;
if(!message.mentions.users) return; if (!message.mentions.users) return;
if(message.mentions.users.first()?.id !== 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; if (!message.content.startsWith(`<@!${this.client.user?.id}>`)) return;
let args = message.content.split(" "); let args = message.content.split(' ');
let command = args[1]; let command = args[1];
args.shift(); args.shift();
args.shift(); args.shift();
args = args.filter(e => e !== ''); args = args.filter((e) => e !== '');
if(args.length === 0) if (args.length === 0) args = [];
args = [];
for(const module of this.loaded_module) { for (const module of this.loaded_module) {
let thisModule: DiscordModule = module[1]; let thisModule: DiscordModule = module[1];
thisModule.GuildOnCommand(command, args, message); thisModule.GuildOnCommand(command, args, message);
if(thisModule.commands && thisModule.commands.includes(command)) if (thisModule.commands && thisModule.commands.includes(command))
thisModule.GuildOnModuleCommand(args, message); thisModule.GuildOnModuleCommand(args, message);
} }
}); });
} }
} }
export default new Discord(); export default new Discord();
+110 -80
View File
@@ -1,10 +1,23 @@
import playdl, { YouTubeVideo } from "play-dl"; import { VoiceChannel, Snowflake, TextChannel, StageChannel, Guild } from 'discord.js';
import { VoiceChannel, Snowflake, TextChannel, StageChannel, Guild } from "discord.js"; import {
import { AudioPlayer, VoiceConnection, createAudioPlayer, joinVoiceChannel, createAudioResource, VoiceConnectionStatus, AudioPlayerStatus, AudioPlayerState, NoSubscriberBehavior, VoiceConnectionState, AudioPlayerError, DiscordGatewayAdapterCreator } from "@discordjs/voice"; AudioPlayer,
import { EventEmitter } from "stream"; 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 DiscordProvider from './Discord';
import Environment from "./Environment"; import Environment from './Environment';
export type ValidTracks = YouTubeVideo; export type ValidTracks = YouTubeVideo;
@@ -13,10 +26,10 @@ if (Environment.get().YOUTUBE_COOKIE_BASE64) {
youtube: { youtube: {
cookie: Buffer.from(Environment.get().YOUTUBE_COOKIE_BASE64, 'base64').toString() cookie: Buffer.from(Environment.get().YOUTUBE_COOKIE_BASE64, 'base64').toString()
} }
}) });
} }
export class Queue { export class Queue {
public track: (ValidTracks)[] = []; public track: ValidTracks[] = [];
} }
export class YouTubeLink { export class YouTubeLink {
@@ -56,14 +69,14 @@ export class VoiceDisconnectedEvent {
} }
export enum DiscordMusicPlayerLoopMode { export enum DiscordMusicPlayerLoopMode {
None = "none", None = 'none',
Current = "current" Current = 'current'
} }
export class DiscordMusicPlayerInstance { export class DiscordMusicPlayerInstance {
public queue: Queue; public queue: Queue;
public player: AudioPlayer; public player: AudioPlayer;
public textChannel?: TextChannel; public textChannel?: TextChannel;
public voiceChannel: (VoiceChannel | StageChannel); public voiceChannel: VoiceChannel | StageChannel;
public voiceConnection?: VoiceConnection; public voiceConnection?: VoiceConnection;
public previousTrack?: ValidTracks; public previousTrack?: ValidTracks;
@@ -72,7 +85,7 @@ export class DiscordMusicPlayerInstance {
public readonly events: EventEmitter; public readonly events: EventEmitter;
constructor({ voiceChannel }: { voiceChannel: (VoiceChannel | StageChannel) }) { constructor({ voiceChannel }: { voiceChannel: VoiceChannel | StageChannel }) {
this.queue = new Queue(); this.queue = new Queue();
this.player = createAudioPlayer({ this.player = createAudioPlayer({
behaviors: { behaviors: {
@@ -85,8 +98,10 @@ export class DiscordMusicPlayerInstance {
this.player.on(AudioPlayerStatus.Idle, async (oldStage, newStage) => { this.player.on(AudioPlayerStatus.Idle, async (oldStage, newStage) => {
//The player stopped //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 // Loop mode is set to current song
if (this.loopMode === DiscordMusicPlayerLoopMode.Current) { if (this.loopMode === DiscordMusicPlayerLoopMode.Current) {
if (this.queue.track.length !== 0) { 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 // There are more songs in the queue, remove finished song and play the next one
if (this.queue.track.length !== 0) { if (this.queue.track.length !== 0) {
let previousTrack = this.queue.track.shift(); let previousTrack = this.queue.track.shift();
if(previousTrack) if (previousTrack) this.previousTrack = previousTrack;
this.previousTrack = previousTrack;
if (this.queue.track.length > 0) { if (this.queue.track.length > 0) {
this.playTrack(this.queue.track[0]); this.playTrack(this.queue.track[0]);
} }
} }
} }
}); });
@@ -133,40 +146,49 @@ export class DiscordMusicPlayerInstance {
return true; return true;
} }
public joinVoiceChannel(voiceChannel: (VoiceChannel | StageChannel), textChannel?: TextChannel) { public joinVoiceChannel(voiceChannel: VoiceChannel | StageChannel, textChannel?: TextChannel) {
const permissions = voiceChannel.permissionsFor(DiscordProvider.client.user!); const permissions = voiceChannel.permissionsFor(DiscordProvider.client.user!);
if (!permissions || !voiceChannel.joinable || !permissions.has("CONNECT")) if (!permissions || !voiceChannel.joinable || !permissions.has('CONNECT'))
throw new Error("No permissions"); throw new Error('No permissions');
if (textChannel) if (textChannel) this.textChannel = textChannel;
this.textChannel = textChannel;
this.voiceConnection = joinVoiceChannel({ this.voiceConnection = joinVoiceChannel({
channelId: this.voiceChannel.id, channelId: this.voiceChannel.id,
guildId: this.voiceChannel.guild.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) => { this.voiceConnection.on(
let currentVC = DiscordProvider.client.guilds.cache.get(voiceChannel.guild.id)?.me?.voice.channel; 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) { if (currentVC && currentVC.id !== this.voiceChannel.id) {
this.voiceChannel = currentVC; this.voiceChannel = currentVC;
} }
}); }
);
this.voiceConnection.on(VoiceConnectionStatus.Disconnected, (oldState: VoiceConnectionState, newState: VoiceConnectionState) => { this.voiceConnection.on(
VoiceConnectionStatus.Disconnected,
(oldState: VoiceConnectionState, newState: VoiceConnectionState) => {
setTimeout(() => { setTimeout(() => {
if (!DiscordProvider.client.guilds.cache.get(voiceChannel.guildId!)!.me!.voice.channelId) { if (
!DiscordProvider.client.guilds.cache.get(voiceChannel.guildId!)!.me!.voice
.channelId
) {
this.events.emit('disconnect', new VoiceDisconnectedEvent(this)); this.events.emit('disconnect', new VoiceDisconnectedEvent(this));
} }
}, 1000); }, 1000);
}); }
);
} }
public async leaveVoiceChannel() { public async leaveVoiceChannel() {
if (this.player) if (this.player) this.player.pause();
this.player.pause();
if (DiscordProvider.client.guilds.cache.get(this.voiceChannel.guild.id)?.me?.voice) { if (DiscordProvider.client.guilds.cache.get(this.voiceChannel.guild.id)?.me?.voice) {
this.voiceConnection?.disconnect(); this.voiceConnection?.disconnect();
@@ -174,18 +196,18 @@ export class DiscordMusicPlayerInstance {
} }
public async pausePlayer() { public async pausePlayer() {
if(this.paused || !this.player) return; if (this.paused || !this.player) return;
if(!this.player.pause(true)) throw new Error('Unable to pause player'); if (!this.player.pause(true)) throw new Error('Unable to pause player');
this.paused = true; this.paused = true;
} }
public async resumePlayer() { public async resumePlayer() {
if(!this.paused || !this.player) return; if (!this.paused || !this.player) return;
if(!this.player.unpause()) throw new Error('Unable to resume player'); if (!this.player.unpause()) throw new Error('Unable to resume player');
this.paused = false; this.paused = false;
} }
public addTrackToQueue(track: (ValidTracks)) { public addTrackToQueue(track: ValidTracks) {
if (this.queue.track.length === 0) { if (this.queue.track.length === 0) {
this.queue.track.push(track); this.queue.track.push(track);
this.playTrack(this.queue.track[0]); this.playTrack(this.queue.track[0]);
@@ -196,7 +218,7 @@ export class DiscordMusicPlayerInstance {
} }
public async playTrack(track: ValidTracks) { public async playTrack(track: ValidTracks) {
if (!this.voiceConnection) throw new Error("No voice connection"); if (!this.voiceConnection) throw new Error('No voice connection');
try { try {
const stream = await playdl.stream(track.url); const stream = await playdl.stream(track.url);
@@ -204,8 +226,8 @@ export class DiscordMusicPlayerInstance {
inputType: stream.type inputType: stream.type
}); });
this.player.play(resource) this.player.play(resource);
this.voiceConnection.subscribe(this.player) this.voiceConnection.subscribe(this.player);
} catch (error: any) { } catch (error: any) {
this.events.emit('error', new PlayerErrorEvent(this, error)); this.events.emit('error', new PlayerErrorEvent(this, error));
this.skipTrack(); this.skipTrack();
@@ -213,14 +235,13 @@ export class DiscordMusicPlayerInstance {
} }
public async skipTrack() { 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) { if (this.queue.track.length > 1) {
this.previousTrack = this.queue.track[0]; this.previousTrack = this.queue.track[0];
this.queue.track.shift(); this.queue.track.shift();
this.playTrack(this.queue.track[0]); this.playTrack(this.queue.track[0]);
} } else {
else {
this.previousTrack = this.queue.track[0]; this.previousTrack = this.queue.track[0];
this.queue.track.shift(); this.queue.track.shift();
this.player.stop(); this.player.stop();
@@ -248,8 +269,7 @@ export class DiscordMusicPlayerInstance {
if (this.voiceConnection) { if (this.voiceConnection) {
this.voiceConnection.removeAllListeners(); this.voiceConnection.removeAllListeners();
if (this.voiceConnection.state.status !== 'destroyed') if (this.voiceConnection.state.status !== 'destroyed') this.voiceConnection.destroy();
this.voiceConnection.destroy();
} }
if (this.player) { if (this.player) {
@@ -266,16 +286,17 @@ export class DiscordMusicPlayerInstance {
const stream = 'https://fakestream:42069/fake/stream/fake/audio/fake.mp3'; const stream = 'https://fakestream:42069/fake/stream/fake/audio/fake.mp3';
const resource = createAudioResource(stream); const resource = createAudioResource(stream);
this.player.play(resource); 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 { class DiscordMusicPlayer {
public GuildQueue = new Map(); public GuildQueue = new Map();
public getGuildInstance(guildId: Snowflake): (DiscordMusicPlayerInstance | null) { public getGuildInstance(guildId: Snowflake): DiscordMusicPlayerInstance | null {
if (!this.isGuildInstanceExists(guildId)) return null; if (!this.isGuildInstanceExists(guildId)) return null;
return this.GuildQueue.get(guildId); return this.GuildQueue.get(guildId);
} }
@@ -284,12 +305,11 @@ class DiscordMusicPlayer {
return this.GuildQueue.has(guildId); 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 })); 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; let guildId: Snowflake = guild instanceof Guild ? guild.id : guild;
if (this.isGuildInstanceExists(guildId)) { if (this.isGuildInstanceExists(guildId)) {
@@ -299,39 +319,48 @@ class DiscordMusicPlayer {
} }
public async searchYouTubeByQuery(query: string) { 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; if (searched.length == 0) return null;
return searched; return searched;
} }
public async searchYouTubeByYouTubeLink(youtubeLink: YouTubeLink) { public async searchYouTubeByYouTubeLink(youtubeLink: YouTubeLink) {
// Search the url // 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) { for (let video of searched) {
if (video.id === youtubeLink.videoId) if (video.id === youtubeLink.videoId) return video;
return video;
} }
// Serch the video Id // 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) { for (let video of searched2) {
if (video.id === youtubeLink.videoId) if (video.id === youtubeLink.videoId) return video;
return video;
} }
// Last resort, search the title // 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) { 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) { for (let video of searched) {
if (video.id === youtubeLink.videoId) if (video.id === youtubeLink.videoId) return video;
return video;
} }
} }
let yt_info = await playdl.video_info("https://www.youtube.com/watch?v=" + youtubeLink.videoId); let yt_info = await playdl.video_info(
if(yt_info) { 'https://www.youtube.com/watch?v=' + youtubeLink.videoId
);
if (yt_info) {
return new YouTubeVideo({ return new YouTubeVideo({
id: yt_info.video_details.id, id: yt_info.video_details.id,
url: yt_info.video_details.url, url: yt_info.video_details.url,
@@ -374,16 +403,17 @@ class DiscordMusicPlayer {
} }
public parseYouTubeLink(query: string): YouTubeLink { 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); let data = this.parseURLQuery(query);
if (!data.v) if (!data.v) throw new Error('YouTube link is invalid');
throw new Error('YouTube link is invalid');
return { return {
videoId: data.v, videoId: data.v,
list: (data.list ? (data.list !== "RDMM" ? data.list : undefined) : undefined) list: data.list ? (data.list !== 'RDMM' ? data.list : undefined) : undefined
} };
} } else if (query.startsWith('https://youtu.be/') || query.startsWith('http://youtu.be/')) {
else if (query.startsWith('https://youtu.be/') || query.startsWith('http://youtu.be/')) {
//Get youtube video id after the url //Get youtube video id after the url
let videoId = query.split('/')[3]; let videoId = query.split('/')[3];
@@ -392,16 +422,17 @@ class DiscordMusicPlayer {
return { return {
videoId: videoId videoId: videoId
} };
} } else if (
else if (query.startsWith('https://www.youtube.com/playlist?list=') || query.startsWith('http://www.youtube.com/playlist?list=')) { query.startsWith('https://www.youtube.com/playlist?list=') ||
query.startsWith('http://www.youtube.com/playlist?list=')
) {
let listId = query.split('?list=')[1]; let listId = query.split('?list=')[1];
return { return {
videoId: "", videoId: '',
list: listId list: listId
} };
} } else {
else {
throw new Error('YouTube link is invalid'); throw new Error('YouTube link is invalid');
} }
} }
@@ -418,7 +449,6 @@ class DiscordMusicPlayer {
} }
return queryObject; return queryObject;
} }
} }
const DiscordMusicPlayer_Instance = new DiscordMusicPlayer(); const DiscordMusicPlayer_Instance = new DiscordMusicPlayer();
+9 -21
View File
@@ -1,20 +1,13 @@
import * as path from "path"; import * as path from 'path';
import * as dotenv from "dotenv"; import * as dotenv from 'dotenv';
import Logger from "../libs/Logger"; import Logger from '../libs/Logger';
const requiredENV = [ const requiredENV = ['NODE_ENV', 'DATABASE_URL', 'DISCORD_TOKEN', 'PRIVATE_BOT', 'OSU_API_KEY'];
'NODE_ENV',
'DATABASE_URL',
'DISCORD_TOKEN',
'PRIVATE_BOT',
'OSU_API_KEY'
];
class Environment { class Environment {
public init(): void { public init(): void {
dotenv.config({ path: path.resolve(__dirname, "../../.env") }); dotenv.config({ path: path.resolve(__dirname, '../../.env') });
for (let param of requiredENV) { for (let param of requiredENV) {
if (this.isUndefinedOrEmpty(process.env[param])) if (this.isUndefinedOrEmpty(process.env[param]))
@@ -22,7 +15,7 @@ class Environment {
} }
// NODE_ENV Checks // 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"'); throw new Error('.env NODE_ENV must be either "production" or "development"');
// TODO: Discord token check // TODO: Discord token check
@@ -31,7 +24,6 @@ class Environment {
} }
public get(): any { public get(): any {
const NODE_ENV = process.env.NODE_ENV; const NODE_ENV = process.env.NODE_ENV;
const DISCORD_TOKEN = process.env.DISCORD_TOKEN; const DISCORD_TOKEN = process.env.DISCORD_TOKEN;
@@ -54,18 +46,14 @@ class Environment {
} }
private isUndefinedOrEmpty(value: String | undefined): boolean { private isUndefinedOrEmpty(value: String | undefined): boolean {
if(typeof value === 'undefined') if (typeof value === 'undefined') return true;
return true;
if(value === undefined) if (value === undefined) return true;
return true;
if(value === '') if (value === '') return true;
return true;
return false; return false;
} }
} }
export default new Environment(); export default new Environment();
+2 -4
View File
@@ -1,11 +1,10 @@
import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
class Prisma { class Prisma {
public client: PrismaClient; public client: PrismaClient;
constructor () { constructor() {
this.client = new PrismaClient; this.client = new PrismaClient();
} }
public init(): void { public init(): void {
@@ -15,7 +14,6 @@ class Prisma {
public end(): void { public end(): void {
this.client.$disconnect(); this.client.$disconnect();
} }
} }
export default new Prisma(); export default new Prisma();
+2 -5
View File
@@ -2,10 +2,9 @@ import { Api } from 'node-osu';
import Environment from './Environment'; import Environment from './Environment';
class osuAPI { class osuAPI {
public client: Api; public client: Api;
constructor () { constructor() {
this.client = new Api(Environment.get().OSU_API_KEY, { this.client = new Api(Environment.get().OSU_API_KEY, {
notFoundAsError: false, notFoundAsError: false,
completeScores: true, completeScores: true,
@@ -21,9 +20,7 @@ class osuAPI {
}); });
} }
public end(): void { public end(): void {}
}
} }
export default new osuAPI(); export default new osuAPI();
+5 -8
View File
@@ -1,19 +1,16 @@
import { User, Snowflake } from "discord.js"; import { User, Snowflake } from 'discord.js';
import Environment from "../providers/Environment"; import Environment from '../providers/Environment';
class Users { class Users {
public static isDeveloper(user: User | Snowflake) { public static isDeveloper(user: User | Snowflake) {
const developers: Snowflake[] = (Environment.get().DEVELOPER_IDS).split(','); const developers: Snowflake[] = Environment.get().DEVELOPER_IDS.split(',');
let userID; let userID;
if(user instanceof User) if (user instanceof User) userID = user.id;
userID = user.id; else userID = user;
else
userID = user;
return developers.includes(userID); return developers.includes(userID);
} }
} }
+110 -106
View File
@@ -1,180 +1,179 @@
import Logger from "../libs/Logger"; import { SlashCommandBuilder } from '@discordjs/builders';
import DiscordProvider from "../providers/Discord";
import { SlashCommandBuilder } from "@discordjs/builders"; import DiscordProvider from '../providers/Discord';
import Logger from '../libs/Logger';
export const GLOBAL_COMMANDS: Object[] = []; export const GLOBAL_COMMANDS: Object[] = [];
export const GUILD_COMMANDS: Object[] = []; export const GUILD_COMMANDS: Object[] = [];
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(new SlashCommandBuilder().setName('help').setDescription('Show help menu'));
.setName('help') GUILD_COMMANDS.push(
.setDescription('Show help menu') new SlashCommandBuilder().setName('ping').setDescription('Measure network latency')
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
.setName('ping') new SlashCommandBuilder().setName('invite').setDescription('Invite me to your server!')
.setDescription('Measure network latency')
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
.setName('invite') new SlashCommandBuilder()
.setDescription('Invite me to your server!')
);
GUILD_COMMANDS.push(new SlashCommandBuilder()
.setName('say') .setName('say')
.setDescription('Make me say something') .setDescription('Make me say something')
.addStringOption(option => option .addStringOption((option) =>
.setName('message') option.setName('message').setDescription('Message you want me to say').setRequired(true)
.setDescription('Message you want me to say')
.setRequired(true)
) )
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
new SlashCommandBuilder()
.setName('interaction') .setName('interaction')
.setDescription('[Developer Only] Manage interaction') .setDescription('[Developer Only] Manage interaction')
.addSubcommand(info => info .addSubcommand((info) =>
.setName('info') info.setName('info').setDescription('[Developer Only] Interaction modules information')
.setDescription('[Developer Only] Interaction modules information')
) )
.addSubcommand(reloadAll => reloadAll .addSubcommand((reloadAll) =>
reloadAll
.setName('reloadall') .setName('reloadall')
.setDescription('[Developer Only] Reload interaction for global and all guilds') .setDescription('[Developer Only] Reload interaction for global and all guilds')
) )
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
new SlashCommandBuilder()
.setName('settings') .setName('settings')
.setDescription('Change settings') .setDescription('Change settings')
.addSubcommand(info => info .addSubcommand((info) =>
info
.setName('setprefix') .setName('setprefix')
.setDescription('Change what prefix to use on this guild') .setDescription('Change what prefix to use on this guild')
.addStringOption(prefix => prefix .addStringOption((prefix) =>
.setName('prefix') prefix.setName('prefix').setDescription('New prefix to use').setRequired(true)
.setDescription('New prefix to use')
.setRequired(true)
) )
) )
.addSubcommand(info => info .addSubcommand((info) =>
info
.setName('setenableserviceannouncement') .setName('setenableserviceannouncement')
.setDescription('Enable or disable service announcement feature') .setDescription('Enable or disable service announcement feature')
.addStringOption(prefix => prefix .addStringOption((prefix) =>
.setName('status') prefix.setName('status').setDescription('New status').setRequired(true)
.setDescription('New status')
.setRequired(true)
) )
) )
.addSubcommand(info => info .addSubcommand((info) =>
info
.setName('setserviceannouncementchannel') .setName('setserviceannouncementchannel')
.setDescription('Set channel where service announcement will be sent') .setDescription('Set channel where service announcement will be sent')
.addChannelOption(prefix => prefix .addChannelOption((prefix) =>
.setName('channel') prefix.setName('channel').setDescription('New status').setRequired(true)
.setDescription('New status')
.setRequired(true)
) )
) )
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
new SlashCommandBuilder()
.setName('membershipscreening') .setName('membershipscreening')
.setDescription('Membership screening') .setDescription('Membership screening')
.addSubcommand(info => info .addSubcommand((info) =>
.setName('info') info.setName('info').setDescription('Show more information for membership screening')
.setDescription('Show more information for membership screening')
) )
.addSubcommand(enable => enable .addSubcommand((enable) =>
.setName('enable') enable.setName('enable').setDescription('Enable membership screening')
.setDescription('Enable membership screening')
) )
.addSubcommand(enable => enable .addSubcommand((enable) =>
.setName('disable') enable.setName('disable').setDescription('Disable membership screening')
.setDescription('Disable membership screening')
) )
.addSubcommand(setrole => setrole .addSubcommand((setrole) =>
setrole
.setName('setrole') .setName('setrole')
.setDescription('Set a role that user will be granted when approved to join') .setDescription('Set a role that user will be granted when approved to join')
.addRoleOption(option => option .addRoleOption((option) =>
option
.setName('role') .setName('role')
.setDescription('Select a role that user will be granted when approved to join') .setDescription(
'Select a role that user will be granted when approved to join'
)
.setRequired(true) .setRequired(true)
) )
) )
.addSubcommand(setchannel => setchannel .addSubcommand((setchannel) =>
setchannel
.setName('setchannel') .setName('setchannel')
.setDescription('Set channel where membership screening approval request will be sent') .setDescription(
.addChannelOption(option => option 'Set channel where membership screening approval request will be sent'
)
.addChannelOption((option) =>
option
.setName('channel') .setName('channel')
.setDescription('Select a channel where approval request will be sent') .setDescription('Select a channel where approval request will be sent')
.setRequired(true) .setRequired(true)
) )
) )
.addSubcommand(createmessage => createmessage .addSubcommand((createmessage) =>
createmessage
.setName('createmessage') .setName('createmessage')
.setDescription('Create greeting message for membership screening into the channel. A message for new commers to read') .setDescription(
'Create greeting message for membership screening into the channel. A message for new commers to read'
)
) )
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
new SlashCommandBuilder()
.setName('osu') .setName('osu')
.setDescription('Interact with the game osu!') .setDescription('Interact with the game osu!')
.addSubcommand(user => user .addSubcommand((user) =>
user
.setName('user') .setName('user')
.setDescription('Get user information on osu!') .setDescription('Get user information on osu!')
.addStringOption(user => user .addStringOption((user) =>
.setName('user') user.setName('user').setDescription('Username or User id').setRequired(true)
.setDescription('Username or User id')
.setRequired(true)
) )
) )
.addSubcommand(beatmap => beatmap .addSubcommand((beatmap) =>
beatmap
.setName('beatmap') .setName('beatmap')
.setDescription('Get beatmap information on osu!') .setDescription('Get beatmap information on osu!')
.addStringOption(user => user .addStringOption((user) =>
.setName('beatmap') user.setName('beatmap').setDescription('Beatmap id').setRequired(true)
.setDescription('Beatmap id')
.setRequired(true)
) )
) )
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
new SlashCommandBuilder()
.setName('userinfo') .setName('userinfo')
.setDescription('Lookup discord user information') .setDescription('Lookup discord user information')
.addSubcommand(user => user .addSubcommand((user) =>
user
.setName('user') .setName('user')
.setDescription('Lookup discord user information') .setDescription('Lookup discord user information')
.addUserOption(user => user .addUserOption((user) =>
.setName('user') user.setName('user').setDescription('Discord user to lookup').setRequired(true)
.setDescription('Discord user to lookup')
.setRequired(true)
) )
) )
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
.setName('stats') new SlashCommandBuilder().setName('stats').setDescription('Show the bot stats')
.setDescription('Show the bot stats')
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
.setName('skip') new SlashCommandBuilder().setName('skip').setDescription('Skip the current song')
.setDescription('Skip the current song')
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
new SlashCommandBuilder()
.setName('nowplaying') .setName('nowplaying')
.setDescription('Show the current song information') .setDescription('Show the current song information')
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
.setName('join') new SlashCommandBuilder().setName('join').setDescription('Join the voice channel')
.setDescription('Join the voice channel')
); );
GUILD_COMMANDS.push(new SlashCommandBuilder() GUILD_COMMANDS.push(
.setName('leave') new SlashCommandBuilder().setName('leave').setDescription('Leave the voice channel')
.setDescription('Leave the voice channel')
); );
export const registerAllGlobalCommands = async () => { export const registerAllGlobalCommands = async () => {
Logger.log('info', `Registering all global interaction commands`); 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 () => { export const unregisterAllGlobalCommands = async () => {
//const commands = await DiscordProvider.client.application?.commands.fetch(); //const commands = await DiscordProvider.client.application?.commands.fetch();
@@ -187,32 +186,38 @@ export const unregisterAllGlobalCommands = async () => {
/*for(const command of commands) { /*for(const command of commands) {
await DiscordProvider.client.application?.commands.delete(command[1]); await DiscordProvider.client.application?.commands.delete(command[1]);
}*/ }*/
};
}
export const registerAllGuildsCommands = async () => { 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); const guildObject = DiscordProvider.client.guilds.cache.get(guild);
if(!guildObject) continue; if (!guildObject) continue;
Logger.log('info', `Registering all interaction commands on guild ${guildObject.name} (${guildObject.id})`); Logger.log(
await DiscordProvider.client.guilds.cache.get(guildObject.id)?.commands.set(JSON.parse(JSON.stringify(GUILD_COMMANDS))); '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 () => { export const unregisterAllGuildsCommands = 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); 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([]); await DiscordProvider.client.guilds.cache.get(guildObject.id)?.commands.set([]);
//const commands = await guildObject.commands.fetch(); //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})`); Logger.log('error', `Cannot unregister all interaction commands on guild ${guildObject.name} (${guildObject.id})`);
} }
}*/ }*/
} }
} };
+180 -92
View File
@@ -1,184 +1,272 @@
import { MessageEmbed, User, MessagePayload, MessageOptions, GuildTextBasedChannel, TextChannel, DMChannel, PartialDMChannel, BaseGuildTextChannel, Message, ColorResolvable, Interaction, InteractionReplyOptions, CommandInteraction } from "discord.js"; import {
import App from ".."; MessageEmbed,
import Logger from "../libs/Logger"; User,
import { HybridInteractionMessage } from "./DiscordModule"; 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 = { const emotes = {
"yumiloading": "<a:yumiloading:983269480085983262>" yumiloading: '<a:yumiloading:983269480085983262>'
}; };
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(); const embed = new MessageEmbed();
embed.setColor(color || '#FFFFFF'); embed.setColor(color || '#FFFFFF');
if(typeof icon === 'undefined') if (typeof icon === 'undefined') embed.setTitle(title);
embed.setTitle(title); else embed.setTitle(`${icon} ${title}`);
else
embed.setTitle(`${icon} ${title}`);
if (typeof description !== 'undefined') if (typeof description !== 'undefined') embed.setDescription(description);
embed.setDescription(description)
if(setTimestamp) if (setTimestamp) embed.setTimestamp();
embed.setTimestamp();
if(typeof user !== 'undefined') if (typeof user !== 'undefined')
embed.footer = { embed.footer = {
text: `${user.username} | v${App.version}`, text: `${user.username} | v${App.version}`,
iconURL: `${user.displayAvatarURL()}?size=4096` iconURL: `${user.displayAvatarURL()}?size=4096`
} };
else else
embed.footer = { embed.footer = {
text: `v${App.version}` text: `v${App.version}`
} };
if (typeof fields !== 'undefined') if (typeof fields !== 'undefined') embed.addFields(fields);
embed.addFields(fields);
return embed; return embed;
} }
export function makeSuccessEmbed(options: any) { 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) { 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) { 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) { 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) { 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; let message;
try { message = await channel.send(options); } try {
catch(error) { message = await channel.send(options);
if(typeof user === 'undefined') { } catch (error) {
return Logger.error(`Cannot find available destinations to send the message CID: ${channel.id} C_ERR: ${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); } try {
catch(errorDM) { message = await user.send(options);
Logger.error(`Cannot find available destinations to send the message CID: ${channel.id} UID: ${user.id} C_ERR: ${error} DM_ERR: ${errorDM}`); } 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; return;
} }
} finally { } finally {
return message; return message;
} }
} }
export async function sendReply(rMessage: Message, options: string | MessagePayload | MessageOptions) { export async function sendReply(
rMessage: Message,
options: string | MessagePayload | MessageOptions
) {
let message; let message;
try { message = await rMessage.reply(options); } try {
catch(error) { message = await rMessage.reply(options);
try { message = await rMessage.author.send(options); } } catch (error) {
catch(errorDM) { try {
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}`); 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; return;
} }
} finally { } finally {
return message; return message;
} }
} }
export async function sendMessageOrInteractionResponse(
export async function sendMessageOrInteractionResponse(data: Message | Interaction, payload: MessageOptions | InteractionReplyOptions, replace = false) { data: Message | Interaction,
payload: MessageOptions | InteractionReplyOptions,
replace = false
) {
const isSlashCommand = data instanceof CommandInteraction && data.isCommand(); const isSlashCommand = data instanceof CommandInteraction && data.isCommand();
const isMessage = data instanceof Message; const isMessage = data instanceof Message;
if(isSlashCommand || (data instanceof Interaction && ( data.isSelectMenu() || data.isButton()))) { if (
if(!data.replied) { isSlashCommand ||
(data instanceof Interaction && (data.isSelectMenu() || data.isButton()))
) {
if (!data.replied) {
let message; let message;
try { try {
if(!data.deferred) if (!data.deferred) return await data.reply(payload as InteractionReplyOptions);
return await data.reply(payload as InteractionReplyOptions); else return await data.editReply(payload);
else } catch (errorDM) {
return await data.editReply(payload); 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;
} }
catch(errorDM) { } else {
Logger.error(`Cannot find available destinations to send the message CID: ${data.channel!.id} UID: ${data.user.id} DM_ERR: ${errorDM}`); 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}`
);
return; return;
} finally { } finally {
return message; return message;
} }
} }
else { } else if (isMessage) return await sendReply(data, payload as MessageOptions);
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}`);
return;
} finally {
return message;
}
}
}
else if(isMessage) return await sendReply(data, payload as MessageOptions);
} }
export async function sendHybridInteractionMessageResponse(data: HybridInteractionMessage, payload: MessageOptions | InteractionReplyOptions, replace = false): (Promise<Message | Interaction | undefined>) { export async function sendHybridInteractionMessageResponse(
data: HybridInteractionMessage,
if(data.isSlashCommand() || data.isButton() || data.isSelectMenu()) { payload: MessageOptions | InteractionReplyOptions,
replace = false
): Promise<Message | Interaction | undefined> {
if (data.isSlashCommand() || data.isButton() || data.isSelectMenu()) {
const messageComponent = data.getMessageComponentInteraction(); const messageComponent = data.getMessageComponentInteraction();
if(!messageComponent.replied) { if (!messageComponent.replied) {
let message; let message;
try { try {
if(!messageComponent.deferred) { if (!messageComponent.deferred) {
await messageComponent.reply(payload as InteractionReplyOptions); await messageComponent.reply(payload as InteractionReplyOptions);
return messageComponent; return messageComponent;
} } else {
else {
await messageComponent.editReply(payload); await messageComponent.editReply(payload);
return messageComponent; return messageComponent;
} }
} } catch (errorDM) {
catch(errorDM) { Logger.error(
Logger.error(`Cannot find available destinations to send the message CID: ${messageComponent.channel!.id} UID: ${messageComponent.user.id} DM_ERR: ${errorDM}`); `Cannot find available destinations to send the message CID: ${
messageComponent.channel!.id
} UID: ${messageComponent.user.id} DM_ERR: ${errorDM}`
);
return; return;
} finally { } finally {
return message; return message;
} }
} } else {
else {
let message; let message;
try { try {
if(replace) if (replace) return (await messageComponent.editReply(payload)) as Message;
return (await messageComponent.editReply(payload) as Message);
else else
return (await messageComponent.followUp(payload as InteractionReplyOptions) as Message); return (await messageComponent.followUp(
} payload as InteractionReplyOptions
catch(errorDM) { )) as Message;
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; return;
} finally { } finally {
return message; return message;
} }
} }
} } else if (data.isMessage())
else if(data.isMessage()) return await sendReply(data.getMessage(), payload as MessageOptions); return await sendReply(data.getMessage(), payload as MessageOptions);
} }
export function getEmotes() { export function getEmotes() {
+55 -39
View File
@@ -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 { export default class DiscordModule {
public id?: string; public id?: string;
public commands?: (string[] | null) = null; public commands?: string[] | null = null;
public commandInteractionName?: (string | null) = null; public commandInteractionName?: string | null = null;
constructor({ id, command, commandInteractionName }: { constructor({
id?: string, id,
command?: (string[] | null), command,
commandInteractionName?: (string | null) commandInteractionName
}: {
id?: string;
command?: string[] | null;
commandInteractionName?: string | null;
} = {}) { } = {}) {
this.id = id; this.id = id;
this.commands = command; this.commands = command;
this.commandInteractionName = commandInteractionName; this.commandInteractionName = commandInteractionName;
} }
Init(): (void | Promise<void | any>) {} Init(): void | Promise<void | any> {}
Ready(): (void | Promise<void | any>) {} Ready(): void | Promise<void | any> {}
GuildOnCommand(command: string, args: any, message: Message): (void | Promise<void | any>) {} GuildOnCommand(command: string, args: any, message: Message): void | Promise<void | any> {}
GuildOnModuleCommand(args: any, message: Message): (void | Promise<void | any>) {} GuildOnModuleCommand(args: any, message: Message): void | Promise<void | any> {}
GuildInteractionCreate(interaction: Interaction): (void | Promise<void | any>) {} GuildInteractionCreate(interaction: Interaction): void | Promise<void | any> {}
GuildModuleInteractionCreate(interaction: Interaction): (void | Promise<void | any>) {} GuildModuleInteractionCreate(interaction: Interaction): void | Promise<void | any> {}
GuildCommandInteractionCreate(interaction: CommandInteraction): (void | Promise<void | any>) {} GuildCommandInteractionCreate(interaction: CommandInteraction): void | Promise<void | any> {}
GuildModuleCommandInteractionCreate(interaction: CommandInteraction): (void | Promise<void | any>) {} GuildModuleCommandInteractionCreate(
interaction: CommandInteraction
): void | Promise<void | any> {}
GuildSelectMenuInteractionCreate(interaction: SelectMenuInteraction): (void | Promise<void | any>) {} GuildSelectMenuInteractionCreate(
interaction: SelectMenuInteraction
): void | Promise<void | any> {}
GuildButtonInteractionCreate(interaction: ButtonInteraction): (void | Promise<void | any>) {} GuildButtonInteractionCreate(interaction: ButtonInteraction): void | Promise<void | any> {}
GuildCreate(guild: Guild): (void | Promise<void | any>) {} GuildCreate(guild: Guild): void | Promise<void | any> {}
GuildMemberAdd(member: GuildMember): (void | Promise<void | any>) {} GuildMemberAdd(member: GuildMember): void | Promise<void | any> {}
GuildMessageCreate(message: Message): (void | Promise<void | any>) {} GuildMessageCreate(message: Message): void | Promise<void | any> {}
} }
export class HybridInteractionMessage { export class HybridInteractionMessage {
public data: Interaction | Message; public data: Interaction | Message;
constructor (data: Interaction | Message) { constructor(data: Interaction | Message) {
this.data = data; this.data = data;
} }
@@ -63,58 +81,56 @@ export class HybridInteractionMessage {
return this.data instanceof Message; return this.data instanceof Message;
} }
public getChannel(): (TextBasedChannel | null) { public getChannel(): TextBasedChannel | null {
return this.data.channel; return this.data.channel;
} }
public getGuild(): (Guild | null) { public getGuild(): Guild | null {
return this.data.guild; return this.data.guild;
} }
public getUser(): (User | null) { public getUser(): User | null {
return (this.isInteraction()) ? this.getInteraction().user : this.getMessage().author return this.isInteraction() ? this.getInteraction().user : this.getMessage().author;
} }
public getMember(): (GuildMember | null) { public getMember(): GuildMember | null {
return (this.data.member as GuildMember); return this.data.member as GuildMember;
} }
public getInteraction(): Interaction { public getInteraction(): Interaction {
if(this.isMessage()) if (this.isMessage()) throw new Error('Unable to cast interaction to message');
throw new Error("Unable to cast interaction to message");
return this.data as Interaction; return this.data as Interaction;
} }
public getSlashCommand(): CommandInteraction { public getSlashCommand(): CommandInteraction {
if(this.isInteraction() && !(this.data as CommandInteraction)) if (this.isInteraction() && !(this.data as CommandInteraction))
throw new Error("Unable to cast to MessageComponentInteraction"); throw new Error('Unable to cast to MessageComponentInteraction');
return this.data as CommandInteraction; return this.data as CommandInteraction;
} }
public getSelectMenu(): SelectMenuInteraction { public getSelectMenu(): SelectMenuInteraction {
if(this.isInteraction() && !(this.data as SelectMenuInteraction)) if (this.isInteraction() && !(this.data as SelectMenuInteraction))
throw new Error("Unable to cast to SelectMenuInteraction"); throw new Error('Unable to cast to SelectMenuInteraction');
return this.data as SelectMenuInteraction; return this.data as SelectMenuInteraction;
} }
public getMessageComponentInteraction(): MessageComponentInteraction { public getMessageComponentInteraction(): MessageComponentInteraction {
if(this.isInteraction() && !(this.data as MessageComponentInteraction)) if (this.isInteraction() && !(this.data as MessageComponentInteraction))
throw new Error("Unable to cast to MessageComponentInteraction"); throw new Error('Unable to cast to MessageComponentInteraction');
return this.data as MessageComponentInteraction; return this.data as MessageComponentInteraction;
} }
public getMessage(): Message { public getMessage(): Message {
if(this.isInteraction()) if (this.isInteraction()) throw new Error('Unable to cast message to interaction');
throw new Error("Unable to cast message to interaction");
return this.data as Message; return this.data as Message;
} }
public getRaw(): (Interaction | Message) { public getRaw(): Interaction | Message {
return this.data; return this.data;
} }
} }