Skip to content
This repository was archived by the owner on Oct 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ CLIENT_ID="bot id here"
TOKEN="bot token here"
MONGODB_URI="mongodb connection url here" # Format: mongodb+srv://<name>:<password>@uri/dbname
TOPGG="your topgg bot access token>" # not required if you don't have a bot on top.gg.
TENOR_KEY="tenor api key" # required for posting gifs in global chat.
TENOR_KEY="tenor api key" # required for posting gifs in global chat.
SENTRY_DSN="your sentry dsn link" # get it from sentry.io
2 changes: 1 addition & 1 deletion src/Commands/Main/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default {
.setDescription(
'[Invite](https://discord.com/api/oauth2/authorize?client_id=769921109209907241&permissions=154820537425&scope=bot%20applications.commands) • [Support](https://discord.gg/6bhXQynAPs) • [Privacy](https://discord-chatbot.gitbook.io/chatbot/important/privacy)')
.setFields(interaction.client.commandsArray)
.setFooter({ text: 'Use /help command to get more info about a command.' })
.setFooter({ text: 'Use /help <command> to get more info about a command.' })
.setColor(colors('chatbot'))
.setTimestamp();

Expand Down
3 changes: 1 addition & 2 deletions src/Commands/Main/setup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { SlashCommandBuilder, PermissionFlagsBits, ChatInputCommandInteraction, ChannelType } from 'discord.js';
import { getDb } from '../../Utils/functions/utils';
import logger from '../../Utils/logger';
import init from '../../Scripts/setup/init';
import reset from '../../Scripts/setup/reset';
import displayEmbed from '../../Scripts/setup/displayEmbed';
Expand Down Expand Up @@ -45,7 +44,7 @@ export default {
switch (subcommand) {
case 'view': displayEmbed.execute(interaction, database); break;
case 'reset': reset.execute(interaction, database); break;
default: init.execute(interaction, database).catch(logger.error);
default: init.execute(interaction, database);
}
},
};
2 changes: 1 addition & 1 deletion src/Commands/Network/deleteMsg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default {
return interaction.reply({ content: `${emojis.no} You are not the author of this message.`, ephemeral: true });
}

await interaction.reply({ content: `${emojis.yes} Deletion in progess! This may take a couple of seconds.`, ephemeral: true }).catch(() => null);
await interaction.reply({ content: `${emojis.yes} Deletion in progess! This may take a few seconds.`, ephemeral: true }).catch(() => null);

messageInDb.channelAndMessageIds.forEach((element) => {
if (!element) return;
Expand Down
2 changes: 1 addition & 1 deletion src/Events/interactionCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default {

if (
interaction.inCachedGuild() &&
!interaction.channel?.permissionsFor(interaction.guild?.members.me as GuildMember)
!interaction.channel?.permissionsFor(interaction.guild.members.me as GuildMember)
.has(requiredPerms)
) {
return interaction.reply({
Expand Down
4 changes: 1 addition & 3 deletions src/Scripts/message/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ export = {
}

if (message.stickers.size > 0 && !message.content) {
message.reply(
'Unfortunately, the sending of stickers within the network is not a feature that is currently available. We apologize for any inconvenience this may cause.',
);
message.reply('Sending stickers within the network is not a feature that is currently available. We apologize for any inconvenience this may cause.');
return false;
}

Expand Down
14 changes: 9 additions & 5 deletions src/Scripts/message/messageTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export = {
const channelInSetup = await db?.setup?.findFirst({ where: { channelId: channel?.channelId } });
const channelToSend = await message.client.channels.fetch(channel.channelId).catch(() => null) as GuildTextBasedChannel | null;

if (!channelToSend) return { unkownChannelId: channel?.channelId } as InvalidChannelId;
if (!channelToSend) return { unknownChannelId: channel?.channelId } as InvalidChannelId;

const replyInDb = replyData?.channelAndMessageIds.find((msg) => msg.channelId === channel.channelId);

Expand Down Expand Up @@ -77,9 +77,13 @@ const createWebhookOptions = (message: NetworkMessage, attachments: AttachmentBu
allowedMentions: { parse: ['users'] },
};

channelInSetup?.compact
? webhookMessage.content = channelInSetup?.profFilter ? message.censored_content : message.content
: webhookMessage.embeds = [channelInSetup?.profFilter ? censoredEmbed : embed];

if (channelInSetup.compact) {
webhookMessage.content = channelInSetup?.profFilter ? message.censored_content : message.content;
}
else {
webhookMessage.embeds = [channelInSetup?.profFilter ? censoredEmbed : embed];
webhookMessage.username = message.client.user.username;
webhookMessage.avatarURL = message.client.user.avatarURL() || undefined;
}
return webhookMessage;
};
66 changes: 40 additions & 26 deletions src/Scripts/setup/displayEmbed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,23 +64,20 @@ export = {
const guildConnected = await network.getServerData({ serverId: interaction.guild?.id });

if (!guildSetup) return interaction.followUp(`${emoji.normal.no} Server is not setup yet. Use \`/setup channel\` first.`);
if (!interaction.guild?.channels.cache.get(guildSetup?.channelId)) {
await setupCollection.delete({ where: { channelId: guildSetup?.channelId } });
return await interaction.followUp(`${emoji.normal.no} Network channel not found. Use \`/setup channel\` to set a new one.`);
}

if (!guildConnected) setupActionButtons.components.at(-1)?.setDisabled(true);

const setupMessage = await interaction.editReply({
content: '',
content: interaction.guild?.channels.cache.get(guildSetup?.channelId)
? ''
: `${emoji.normal.no} Automatically disconnected due to error receiving network messages. Change the channel to use the network.`,
embeds: [await setupEmbed.default()],
components: [customizeMenu, setupActionButtons],
});

const filter = (m: Interaction) => m.user.id === interaction.user.id;
const buttonCollector = setupMessage.createMessageComponentCollector({
filter,
time: 60_000,
idle: 60_000,
componentType: ComponentType.Button,
});

Expand All @@ -97,14 +94,14 @@ export = {
case 'compact':
await setupCollection?.updateMany({
where: { guildId: interaction.guild?.id },
data: { date: new Date(), compact: !guildSetup?.compact },
data: { compact: !guildSetup?.compact },
});
break;

case 'profanity':
await setupCollection?.updateMany({
where: { guildId: interaction.guild?.id },
data: { date: new Date(), profFilter: !guildSetup?.profFilter },
data: { profFilter: !guildSetup?.profFilter },
});
break;

Expand All @@ -115,7 +112,7 @@ export = {

if (connectedChannel?.type !== ChannelType.GuildText) {
await settingsMenu.reply({
content: 'Cannot edit setup for selected channel. If you think this is a mistake report this to the developers.',
content: 'Cannot edit setup for selected channel. If you think this is a mistake report it to the developers.',
ephemeral: true,
});
break;
Expand All @@ -129,7 +126,7 @@ export = {

guildSetup = await setupCollection?.update({
where: { channelId: connectedChannel.id },
data: { date: new Date(), webhook: null },
data: { webhook: null },
});

await settingsMenu.reply({
Expand All @@ -151,10 +148,7 @@ export = {
});
}
catch {
interaction.reply({
content: 'Please grant me `Manage Webhook` permissions for this to work.',
ephemeral: true,
});
interaction.editReply('Please grant me `Manage Webhook` permissions for this to work.');
return;
}

Expand All @@ -163,7 +157,6 @@ export = {
await setupCollection?.updateMany({
where: { guildId: interaction.guild?.id },
data: {
date: new Date(),
webhook: { set: { id: webhook.id, token: `${webhook.token}`, url: webhook.url } },
},
});
Expand Down Expand Up @@ -249,14 +242,33 @@ export = {
componentType: ComponentType.ChannelSelect,
idle: 20_000,
});
newChannelSelect.once('collect', async (SelectInteraction) => {
await network.updateData({ channelId: guildSetup?.channelId }, { channelId: SelectInteraction?.values[0] });
newChannelSelect.once('collect', async (select) => {
const oldchannel = select.guild?.channels.cache.get(`${guildSetup?.channelId}`);
const channel = select.guild?.channels.cache.get(select?.values[0]);
let webhook = undefined;

if (oldchannel?.type !== ChannelType.GuildText || channel?.type !== ChannelType.GuildText) return; // so TS doesnt complain

if (guildSetup?.webhook) {
// delete the old webhook
oldchannel?.fetchWebhooks().then(promisehook => {
promisehook.find((hook) => hook.owner?.id === hook.client.user?.id)?.delete().catch(() => null);
}).catch(() => null);

// create a webhook in the new channel
webhook = await channel.createWebhook({ name: 'ChatBot Network', avatar: select.client.user.avatarURL() });
}

await network.updateData({ channelId: guildSetup?.channelId }, { channelId: select?.values[0] });
guildSetup = await setupCollection.update({
where: { channelId: guildSetup?.channelId },
data: { channelId: SelectInteraction?.values[0] },
data: {
channelId: channel.id,
webhook: webhook ? { set: { id: webhook.id, token: `${webhook.token}`, url: webhook.url } } : null,
},
});

await SelectInteraction?.update({
await select?.update({
content: 'Channel successfully set!',
components: [],
});
Expand All @@ -265,6 +277,8 @@ export = {
break;
}
}
await setupCollection.updateMany({ where: { guildId: interaction.guild?.id }, data: { date: new Date() } });

settingsMenu.replied || settingsMenu.deferred
? interaction.editReply({ embeds: [await setupEmbed.default()] })
: settingsMenu.update({ embeds: [await setupEmbed.default()] });
Expand Down Expand Up @@ -355,19 +369,19 @@ class SetupEmbedGenerator {
{
name: 'Network State',
value: stripIndent`
**Connected:** ${status}
**Channel:** ${channel}
**Last Edited:** <t:${lastEditedTimestamp}:R>
`,
**Connected:** ${status}
**Channel:** ${channel || 'None.'}
**Last Edited:** <t:${lastEditedTimestamp}:R>
`,
inline: true,
},
{
name: 'Style',
value: stripIndent`
**Compact:** ${compact}
**Profanity Filter:** ${profanity}
**Profanity Filter:** ${profanity}
**Webhook Messages:** ${webhook}
`,
`,
inline: true,
},
{
Expand Down
20 changes: 11 additions & 9 deletions src/Scripts/setup/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,34 @@ export = {
if (numOfConnections > 1) {
await destination?.send(stripIndents`
This channel has been connected to the chat network. You are currently with ${numOfConnections} other servers, Enjoy! ${emoji.normal.clipart}
**⚠️ This is not an __AI Chat__, but a chat network that allows you to connect to multiple servers and communicate with *__real__* members. ⚠️**`);
**⚠️ This is not an __AI Chat__, but a chat network that allows you to connect to multiple servers and communicate with *__real__* members. ⚠️**`);
}
else {
await destination?.send(stripIndents`
This channel has been connected to the chat network, though no one else is there currently... *cricket noises* ${emoji.normal.clipart}
**⚠️ This is not an __AI Chat__, but a chat network that allows you to connect to multiple servers and communicate with *__real__* members. ⚠️**`);
This channel has been connected to the chat network, though no one else is there currently... *cricket noises* ${emoji.normal.clipart}
**⚠️ This is not an __AI Chat__, but a chat network that allows you to connect to multiple servers and communicate with *__real__* members. ⚠️**`);
}
logger.info(`${interaction.guild?.name} (${interaction.guildId}) has joined the network.`);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
catch (err: any) {
logger.error(err);
if (err.message === 'Missing Permissions' || err.message === 'Missing Access') {
return interaction.reply('I don\'t have the required permissions and/or access to the selected channel to execute this command.');
interaction.editReply(`${emoji.normal.no} I don't have the required permissions and/or access to the selected channel to execute this command.`);
}
else {
interaction.followUp(`An error occurred while connecting to the chat network! \`\`\`js\n${err.message}\`\`\``);
}
logger.error(err);
interaction.followUp(`An error occurred while connecting to the chat network! \`\`\`js\n${err.message}\`\`\``);
network.disconnect(interaction.guild?.id as string);
await setupList?.delete({ where: { channelId: destination?.id } });
return;
}

interaction.client.sendInNetwork(stripIndents`
A new server has joined us in the Network! ${emoji.normal.clipart}
A new server has joined us in the Network! ${emoji.normal.clipart}

**Server Name:** __${interaction.guild?.name}__
**Member Count:** __${interaction.guild?.memberCount}__
**Server Name:** __${interaction.guild?.name}__
**Member Count:** __${interaction.guild?.memberCount}__
`);

displayEmbed.execute(interaction, database);
Expand Down
8 changes: 4 additions & 4 deletions src/Structures/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs';
import logger from '../Utils/logger';
import emojis from '../Utils/JSON/emoji.json';
import project from '../../package.json';
import { Client, Collection, ActivityType, EmbedBuilder, TextChannel, MessageCreateOptions } from 'discord.js';
import { Client, Collection, ActivityType, EmbedBuilder, MessageCreateOptions, GuildTextBasedChannel } from 'discord.js';
import { join } from 'path';
import { colors, constants } from '../Utils/functions/utils';
import { prisma } from '../Utils/db';
Expand Down Expand Up @@ -52,10 +52,10 @@ export class ChatBot extends Client {
});
}

public async sendErrorToChannel(client: Client, embedTitle: string, ErrorStack: unknown, channel?: TextChannel | null) {
const errorChannel = await client.channels.fetch(constants.channel.errorlogs);
public async sendErrorToChannel(embedTitle: string, ErrorStack: unknown, channel?: GuildTextBasedChannel) {
const errorChannel = await this.channels.fetch(constants.channel.errorlogs);
const errorEmbed = new EmbedBuilder()
.setAuthor({ name: 'ChatBot Error Logs', iconURL: client.user?.avatarURL() || undefined })
.setAuthor({ name: 'ChatBot Error Logs', iconURL: this.user?.avatarURL() || undefined })
.setTitle(embedTitle)
.setDescription('```js\n' + ErrorStack + '```')
.setColor(colors('invisible'))
Expand Down
3 changes: 1 addition & 2 deletions src/Structures/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export class NetworkManager {

/**
* Insert a guild & channel into connectedList collection.
* Returns **null** if channel is already connected
*/
public async connect(guild: Guild | null, channel: GuildTextBasedChannel | undefined | null) {
const channelExists = await prisma.connectedList.findFirst({
Expand All @@ -38,7 +37,7 @@ export class NetworkManager {
},
});

if (channelExists) return null;
if (channelExists) return undefined;
if (!guild || !channel) throw new Error('Invalid arguments provided.');

return await prisma.connectedList.create({
Expand Down
2 changes: 1 addition & 1 deletion src/Utils/functions/paginator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function paginate(interaction: CommandInteraction, pages: EmbedBuil
};
const listMessage = interaction.replied ? await interaction.followUp(data) : await interaction.reply(data);

const col = listMessage.createMessageComponentCollector({ filter: i => i.user.id === interaction.user.id, time, componentType: ComponentType.Button });
const col = listMessage.createMessageComponentCollector({ filter: i => i.user.id === interaction.user.id, idle: time, componentType: ComponentType.Button });

col.on('collect', (i) => {
if (i.customId === '1') {--pagenumber, index--;}
Expand Down