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
27 changes: 12 additions & 15 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,24 @@ type HubModerator {
// spamFilter Boolean @default(true)
// }

type hubBlacklist {
reason String
expires DateTime?
hubId String @db.ObjectId
}

model blacklistedServers {
id String @id @default(auto()) @map("_id") @db.ObjectId
serverId String
id String @id @default(auto()) @map("_id") @db.ObjectId
serverId String @unique
serverName String
expires DateTime?
reason String
hub hubs @relation(fields: [hubId], references: [id])
hubId String @db.ObjectId
hubs hubBlacklist[]
}

model blacklistedUsers {
id String @id @default(auto()) @map("_id") @db.ObjectId
userId String @unique
notified Boolean
reason String
expires DateTime?
id String @id @default(auto()) @map("_id") @db.ObjectId
userId String @unique
username String
hub hubs @relation(fields: [hubId], references: [id])
hubId String @db.ObjectId
hubs hubBlacklist[]
}

model connectedList {
Expand Down Expand Up @@ -103,8 +102,6 @@ model hubs {
messages messageData[]
moderators HubModerator[]
connections connectedList[]
blacklistedUsers blacklistedUsers[]
blacklistedServers blacklistedServers[]
// approved Boolean @default(false)
// official Boolean @default(false)
}
Expand Down
154 changes: 154 additions & 0 deletions src/Commands/Apps/blacklist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { ActionRowBuilder, ApplicationCommandType, ButtonBuilder, ButtonStyle, ContextMenuCommandBuilder, EmbedBuilder, MessageContextMenuCommandInteraction, ModalBuilder, TextInputBuilder, TextInputStyle } from 'discord.js';
import { getDb } from '../../Utils/utils';
import { captureException } from '@sentry/node';
import { addServerBlacklist, addUserBlacklist, scheduleUnblacklist } from '../../Utils/blacklist';
import emojis from '../../Utils/JSON/emoji.json';

export default {
description: 'Blacklist the user or server that sent the message from the hub.',
data: new ContextMenuCommandBuilder()
.setName('Add to Blacklist')
.setType(ApplicationCommandType.Message)
.setDMPermission(false),
async execute(interaction: MessageContextMenuCommandInteraction) {
const db = getDb();
const messageInDb = await db.messageData.findFirst({ where: {
channelAndMessageIds: { some: { messageId: interaction.targetId } },
hub: {
OR: [
{ moderators: { some: { userId: interaction.user.id } } },
{ ownerId: interaction.user.id },
],
},
},
});

if (!messageInDb) return interaction.reply({ content: 'This message was not sent in the network or has expired.', ephemeral: true });

const embed = new EmbedBuilder()
.setTitle('Blacklist')
.setDescription('Blacklist a user or server from this hub. This will prevent them from sending messages in this hub.')
.setColor('Blurple');

const buttons = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId('blacklist_user')
.setLabel('Blacklist User')
.setStyle(ButtonStyle.Secondary)
.setEmoji('👤'),
new ButtonBuilder()
.setCustomId('blacklist_server')
.setLabel('Blacklist Server')
.setStyle(ButtonStyle.Secondary)
.setEmoji('🏠'),
);

const reply = await interaction.reply({ embeds: [embed], components: [buttons] });

const collector = reply.createMessageComponentCollector({ filter: (i) => i.user.id === interaction.user.id, idle: 60000 });
collector.on('collect', async (i) => {
if (!messageInDb.hubId) return;

const modal = new ModalBuilder()
.setTitle('Blacklist')
.setCustomId(i.id)
.addComponents(
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
.setCustomId('reason')
.setLabel('Reason')
.setPlaceholder('What is the reason for this blacklist?')
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(500),
),
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
.setCustomId('minutes')
.setLabel('Minutes')
.setPlaceholder('How many minutes should this blacklist last?')
.setStyle(TextInputStyle.Short)
.setMaxLength(2)
.setRequired(false),
),
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
.setCustomId('hours')
.setLabel('Hours')
.setPlaceholder('How many hours should this blacklist last?')
.setStyle(TextInputStyle.Short)
.setMaxLength(2)
.setRequired(false),
),
new ActionRowBuilder<TextInputBuilder>().addComponents(
new TextInputBuilder()
.setCustomId('days')
.setLabel('Days')
.setPlaceholder('How many days should this blacklist last?')
.setStyle(TextInputStyle.Short)
.setMaxLength(2)
.setRequired(false),
),
);

await i.showModal(modal);

const modalResp = await i.awaitModalSubmit({ time: 60000 })
.catch((e) => {
!e.message.includes('with reason: time') ? captureException(e) : null;
return null;
});

if (modalResp?.customId !== i.id) return;

await modalResp.deferUpdate();

const reason = modalResp.fields.getTextInputValue('reason');
const mins = parseInt(modalResp.fields.getTextInputValue('minutes')) || 0;
const hours = parseInt(modalResp.fields.getTextInputValue('hours')) || 0;
const days = parseInt(modalResp.fields.getTextInputValue('days')) || 0;

let expires = undefined;
if (mins || hours || days) expires = new Date();
if (mins) expires?.setMinutes(expires.getMinutes() + mins);
if (hours) expires?.setHours(expires.getHours() + hours);
if (days) expires?.setDate(expires.getDate() + days);

const successEmbed = new EmbedBuilder()
.setColor('Green')
.addFields(
{
name: 'Reason',
value: reason ? reason : 'No reason provided.',
inline: true,
},
{
name: 'Expires',
value: expires ? `<t:${Math.round(expires.getTime() / 1000)}:R>` : 'Never.',
inline: true,
},
);


if (i.customId === 'blacklist_user') {
const user = await i.client.users.fetch(messageInDb.authorId).catch(() => null);
successEmbed.setDescription(`${emojis.normal.tick} **${user?.username}** has been successfully blacklisted!`);
await addUserBlacklist(messageInDb.hubId, i.user, messageInDb.authorId, reason, expires);

if (expires) scheduleUnblacklist('user', i.client, messageInDb.authorId, messageInDb.hubId, expires);

await modalResp.editReply({ embeds: [successEmbed], components: [] });
}

else if (i.customId === 'blacklist_server') {
successEmbed.setDescription(`${emojis.normal.tick} **${i.client.guilds.cache.get(messageInDb.serverId)?.name}** has been successfully blacklisted!`);
await addServerBlacklist(messageInDb.serverId, i.user, messageInDb.hubId, reason, expires);
await db.connectedList.deleteMany({ where: { serverId: messageInDb.serverId, hubId: messageInDb.hubId } });

if (expires) scheduleUnblacklist('server', i.client, messageInDb.serverId, messageInDb.hubId, expires);

await modalResp.editReply({ embeds: [successEmbed], components: [] });
}
});
},
};
2 changes: 2 additions & 0 deletions src/Commands/Apps/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,13 @@ export default {
if (!e.message.includes('with reason: time')) {
logger.error(e);
captureException(e);

interaction.followUp({
content: `${emojis.normal.no} An error occored while making the report.`,
ephemeral: true,
});
}
return null;
});
});
},
Expand Down
48 changes: 23 additions & 25 deletions src/Commands/Network/blacklist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,6 @@ export default {
.setDescription('The user to remove from the blacklist. User tag also works.')
.setAutocomplete(true)
.setRequired(true),
)
.addStringOption(string =>
string
.setName('reason')
.setDescription('The reason for blacklisting the server.'),
),
)
.addSubcommand(subcommand =>
Expand All @@ -124,11 +119,6 @@ export default {
.setDescription('The server to remove from the blacklist.')
.setAutocomplete(true)
.setRequired(true),
)
.addStringOption(string =>
string
.setName('reason')
.setDescription('The reason for blacklisting the server.'),
),
),
)
Expand Down Expand Up @@ -204,16 +194,21 @@ export default {
const userOpt = interaction.options.get('user');

if (!userOpt?.focused || typeof userOpt.value !== 'string') return;
const userHubMod = await db.hubs.findFirst({
where: {
name: focusedHub.value,
OR: [
{ ownerId: interaction.user.id },
{ moderators: { some: { userId: interaction.user.id } } },
],
},
});

if (!userHubMod) return interaction.respond([]);

const filteredUsers = await db.blacklistedUsers.findMany({
where: {
hub: {
name: focusedHub.value,
OR: [
{ ownerId: interaction.user.id },
{ moderators: { some: { userId: interaction.user.id } } },
],
},
hubs: { some: { hubId: userHubMod.id } },
OR: [
{ username: { mode: 'insensitive', contains: userOpt.value } },
{ userId: { mode: 'insensitive', contains: userOpt.value } },
Expand All @@ -228,18 +223,21 @@ export default {
}
case 'server': {
const serverOpt = interaction.options.get('server', true);
const serverHubMod = await db.hubs.findFirst({
where: {
name: focusedHub.value,
OR: [
{ ownerId: interaction.user.id },
{ moderators: { some: { userId: interaction.user.id } } },
],
},
});
if (!serverOpt.focused || typeof serverOpt.value !== 'string' || !serverHubMod) return;

if (!serverOpt.focused || typeof serverOpt.value !== 'string') return;

const allServers = await db.blacklistedServers.findMany({
where: {
hub: {
name: focusedHub.value,
OR: [
{ ownerId: interaction.user.id },
{ moderators: { some: { userId: interaction.user.id } } },
],
},
hubs: { some: { hubId: serverHubMod.id } },
OR: [
{ serverName: { mode: 'insensitive', contains: serverOpt.value } },
{ serverId: { mode: 'insensitive', contains: serverOpt.value } },
Expand Down
14 changes: 5 additions & 9 deletions src/Events/messageReactionAdd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MessageReaction, PartialMessageReaction, PartialUser, User } from 'disc
import { getDb } from '../Utils/utils';
import updateMessageReactions from '../Scripts/reactions/updateMessage';
import { HubSettingsBitField } from '../Utils/hubSettingsBitfield';
import { findBlacklistedServer, findBlacklistedUser } from '../Utils/blacklist';

export default {
name: 'messageReactionAdd',
Expand All @@ -17,19 +18,14 @@ export default {
if (
!messageInDb?.hub ||
!messageInDb?.hubId ||
!new HubSettingsBitField(messageInDb.hub?.settings).has('Reactions')
!new HubSettingsBitField(messageInDb.hub?.settings).has('Reactions') ||
!reaction.message.inGuild()
) return;

const userBlacklisted = await db.blacklistedUsers.findFirst({
where: { userId: user.id, hubId: messageInDb.hubId },
});
const serverBlacklisted = await db.blacklistedServers.findFirst({
where: { serverId: reaction.message.guild?.id, hubId: messageInDb.hubId },
});

const userBlacklisted = await findBlacklistedUser(messageInDb.hubId, user.id);
const serverBlacklisted = await findBlacklistedServer(messageInDb.hubId, reaction.message.guild.id);
if (userBlacklisted || serverBlacklisted) return;


const cooldown = reaction.client.reactionCooldowns.get(user.id);
if (cooldown && cooldown > Date.now()) return;
reaction.client.reactionCooldowns.set(user.id, Date.now() + 5000);
Expand Down
15 changes: 9 additions & 6 deletions src/Scripts/blacklist/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ module.exports = {
// repeat until you reach the end

if (serverOpt == 'server') {
const result = await getDb().blacklistedServers.findMany({ where: { hubId: hub.id } });
const result = await getDb().blacklistedServers.findMany({ where: { hubs: { some: { hubId: hub.id } } } });

result.forEach((data, index) => {
const hubData = data.hubs.find(({ hubId }) => hubId === hub.id);
fields.push({
name: data.serverName,
value: stripIndents`
**ServerId:** ${data.serverId}
**Reason:** ${data.reason}
**Expires:** ${!data.expires ? 'Never.' : `<t:${Math.ceil(data.expires.getTime() / 1000)}:R>`}
**Reason:** ${hubData?.reason}
**Expires:** ${!hubData?.expires ? 'Never.' : `<t:${Math.ceil(hubData.expires.getTime() / 1000)}:R>`}
`,
});

Expand All @@ -48,15 +49,17 @@ module.exports = {
});
}
else if (serverOpt == 'user') {
const result = await getDb().blacklistedUsers.findMany({ where: { hubId: hub.id } });
const result = await getDb().blacklistedUsers.findMany({ where: { hubs: { some: { hubId: hub.id } } } });

result.forEach((data, index) => {
const hubData = data.hubs.find(({ hubId }) => hubId === hub.id);

fields.push({
name: data.username,
value: stripIndents`
**UserID:** ${data.userId}
**Reason:** ${data.reason}
**Expires:** ${!data.expires ? 'Never.' : `<t:${Math.ceil(data.expires.getTime() / 1000)}:R>`}
**Reason:** ${hubData?.reason}
**Expires:** ${!hubData?.expires ? 'Never.' : `<t:${Math.ceil(hubData.expires.getTime() / 1000)}:R>`}
`,
});

Expand Down
Loading