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
75 changes: 37 additions & 38 deletions src/commands/context-menu/deleteMsg.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import BaseCommand from '#main/core/BaseCommand.js';
import Constants, { emojis } from '#main/config/Constants.js';
import db from '#utils/Db.js';
import BaseCommand from '#main/core/BaseCommand.js';
import db from '#main/utils/Db.js';
import {
findOriginalMessage,
getBroadcasts,
getOriginalMessage,
OriginalMessage,
} from '#main/utils/network/messageUtils.js';
import { isStaffOrHubMod } from '#utils/hub/utils.js';
import { logMsgDelete } from '#utils/HubLogger/ModLogs.js';
import { t } from '#utils/Locale.js';
import { deleteMessageFromHub, isDeleteInProgress } from '#utils/moderation/deleteMessage.js';
import { Hub, HubLogConfig } from '@prisma/client';
import {
ApplicationCommandType,
MessageContextMenuCommandInteraction,
RESTPostAPIApplicationCommandsJSONBody,
} from 'discord.js';
import { isStaffOrHubMod } from '#utils/hub/utils.js';
import { deleteMessageFromHub, isDeleteInProgress } from '#utils/moderation/deleteMessage.js';
import { originalMessages, Hub, broadcastedMessages, HubLogConfig } from '@prisma/client';

type OriginalMsgT = originalMessages & {
hub: Hub & { logConfig: HubLogConfig[] };
broadcastMsgs: broadcastedMessages[];
};

export default class DeleteMessage extends BaseCommand {
readonly data: RESTPostAPIApplicationCommandsJSONBody = {
Expand All @@ -32,43 +33,37 @@ export default class DeleteMessage extends BaseCommand {
await interaction.deferReply({ ephemeral: true });

const originalMsg = await this.getOriginalMessage(interaction.targetId);
if (!(await this.validateMessage(interaction, originalMsg))) return;
const hub = await this.fetchHub(originalMsg?.hubId);

const validation = await this.validateMessage(interaction, originalMsg, hub);
if (!validation) return;

await this.processMessageDeletion(interaction, originalMsg as OriginalMsgT);
await this.processMessageDeletion(interaction, originalMsg!, validation.hub);
}

private async getOriginalMessage(messageId: string) {
const originalMsg = await db.originalMessages.findFirst({
where: { messageId },
include: { hub: { include: { logConfig: true } }, broadcastMsgs: true },
});

if (originalMsg) return originalMsg;

const broadcastedMsg = await db.broadcastedMessages.findFirst({
where: { messageId },
include: { originalMsg: { include: { hub: true, broadcastMsgs: true } } },
});

return broadcastedMsg?.originalMsg ?? null;
const originalMsg =
(await getOriginalMessage(messageId)) ?? (await findOriginalMessage(messageId));
return originalMsg;
}

private async processMessageDeletion(
interaction: MessageContextMenuCommandInteraction,
originalMsg: OriginalMsgT,
originalMsg: OriginalMessage,
hub: Hub & { logConfig: HubLogConfig[] },
): Promise<void> {
const { hub } = originalMsg;
const { userManager } = interaction.client;
const locale = await userManager.getUserLocale(interaction.user.id);

await interaction.editReply(
`${emojis.yes} Your request has been queued. Messages will be deleted shortly...`,
);

const broadcasts = await getBroadcasts(originalMsg.messageId, originalMsg.hubId);
const { deletedCount } = await deleteMessageFromHub(
hub.id,
originalMsg.messageId,
originalMsg.broadcastMsgs,
Object.values(broadcasts),
);

await interaction
Expand All @@ -77,24 +72,28 @@ export default class DeleteMessage extends BaseCommand {
emoji: emojis.yes,
user: `<@${originalMsg.authorId}>`,
deleted: `${deletedCount}`,
total: `${originalMsg.broadcastMsgs.length}`,
total: `${broadcasts.length}`,
}),
)
.catch(() => null);

await this.logDeletion(interaction, hub, originalMsg);
}

private async fetchHub(hubId?: string) {
if (!hubId) return null;
return await db.hub.findUnique({ where: { id: hubId }, include: { logConfig: true } });
}

private async validateMessage(
interaction: MessageContextMenuCommandInteraction,
originalMsg:
| (originalMessages & { hub: Hub | null; broadcastMsgs: broadcastedMessages[] })
| null,
): Promise<boolean> {
originalMsg: OriginalMessage | null,
hub: (Hub & { logConfig: HubLogConfig[] }) | null,
) {
const { userManager } = interaction.client;
const locale = await userManager.getUserLocale(interaction.user.id);

if (!originalMsg?.hub) {
if (!originalMsg || !hub) {
await interaction.editReply(t('errors.unknownNetworkMessage', locale, { emoji: emojis.no }));
return false;
}
Expand All @@ -110,19 +109,19 @@ export default class DeleteMessage extends BaseCommand {

if (
interaction.user.id !== originalMsg.authorId &&
!isStaffOrHubMod(interaction.user.id, originalMsg.hub)
!isStaffOrHubMod(interaction.user.id, hub)
) {
await interaction.editReply(t('errors.notMessageAuthor', locale, { emoji: emojis.no }));
return false;
}

return true;
return { hub };
}

private async logDeletion(
interaction: MessageContextMenuCommandInteraction,
hub: Hub & { logConfig: HubLogConfig[] },
originalMsg: OriginalMsgT,
originalMsg: OriginalMessage,
): Promise<void> {
if (!isStaffOrHubMod(interaction.user.id, hub)) return;

Expand All @@ -138,7 +137,7 @@ export default class DeleteMessage extends BaseCommand {

await logMsgDelete(interaction.client, messageContent, hub, {
userId: originalMsg.authorId,
serverId: originalMsg.serverId,
serverId: originalMsg.guildId,
modName: interaction.user.username,
imageUrl,
});
Expand Down
71 changes: 30 additions & 41 deletions src/commands/context-menu/editMsg.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import Constants, { ConnectionMode, emojis } from '#main/config/Constants.js';
import BaseCommand from '#main/core/BaseCommand.js';
import { RegisterInteractionHandler } from '#main/decorators/Interaction.js';
import HubSettingsManager from '#main/managers/HubSettingsManager.js';
import VoteBasedLimiter from '#main/modules/VoteBasedLimiter.js';
import { SerializedHubSettings } from '#main/modules/BitFields.js';
import Constants, { ConnectionMode, emojis } from '#main/config/Constants.js';
import VoteBasedLimiter from '#main/modules/VoteBasedLimiter.js';
import { fetchHub } from '#main/utils/hub/utils.js';
import {
findOriginalMessage,
getBroadcasts,
getOriginalMessage,
OriginalMessage,
} from '#main/utils/network/messageUtils.js';
import { CustomID } from '#utils/CustomID.js';
import db from '#utils/Db.js';
import { getAttachmentURL } from '#utils/ImageUtils.js';
import { t } from '#utils/Locale.js';
import { censor } from '#utils/ProfanityUtils.js';
import { containsInviteLinks, handleError, replaceLinks } from '#utils/Utils.js';
import { originalMessages } from '@prisma/client';
import {
ActionRowBuilder,
ApplicationCommandType,
Expand All @@ -24,7 +31,6 @@ import {
User,
userMention,
} from 'discord.js';
import { getAttachmentURL } from '#utils/ImageUtils.js';

interface ImageUrls {
oldURL?: string | null;
Expand Down Expand Up @@ -56,19 +62,9 @@ export default class EditMessage extends BaseCommand {
return;
}

let messageInDb = await db.originalMessages.findFirst({
where: { messageId: interaction.targetId },
include: { hub: true, broadcastMsgs: true },
});

if (!messageInDb) {
const broadcastedMsg = await db.broadcastedMessages.findFirst({
where: { messageId: interaction.targetId },
include: { originalMsg: { include: { hub: true, broadcastMsgs: true } } },
});

messageInDb = broadcastedMsg?.originalMsg ?? null;
}
const messageInDb =
(await getOriginalMessage(interaction.targetId)) ??
(await findOriginalMessage(interaction.targetId));

if (!messageInDb) {
await interaction.reply({
Expand Down Expand Up @@ -120,31 +116,23 @@ export default class EditMessage extends BaseCommand {
return;
}

let targetMsgData = await db.originalMessages.findFirst({
where: { messageId: target.id },
include: { hub: true, broadcastMsgs: true },
});
const targetMsgData =
(await getOriginalMessage(target.id)) ?? (await findOriginalMessage(target.id));

if (!targetMsgData) {
const broadcastedMsg = await db.broadcastedMessages.findFirst({
where: { messageId: target.id },
include: { originalMsg: { include: { hub: true, broadcastMsgs: true } } },
});

targetMsgData = broadcastedMsg?.originalMsg ?? null;
const unknownMsgErr = t('errors.unknownNetworkMessage', locale, { emoji: emojis.no });
if (!targetMsgData?.hubId) {
await interaction.editReply(unknownMsgErr);
return;
}

if (!targetMsgData?.hub) {
await interaction.editReply(t('errors.unknownNetworkMessage', locale, { emoji: emojis.no }));
const hub = await fetchHub(targetMsgData.hubId);
if (!hub) {
await interaction.editReply(unknownMsgErr);
return;
}

// get the new message input by user
const userInput = interaction.fields.getTextInputValue('newMessage');
const settingsManager = new HubSettingsManager(
targetMsgData.hub.id,
targetMsgData.hub.settings,
);
const settingsManager = new HubSettingsManager(targetMsgData.hubId, hub.settings);
const messageToEdit = this.sanitizeMessage(userInput, settingsManager.getAllSettings());

if (settingsManager.getSetting('BlockInvites') && containsInviteLinks(messageToEdit)) {
Expand All @@ -155,17 +143,18 @@ export default class EditMessage extends BaseCommand {
const imageURLs = await this.getImageURLs(target, targetMsgData.mode, messageToEdit);
const newContents = this.getCompactContents(messageToEdit, imageURLs);
const newEmbeds = await this.buildEmbeds(target, targetMsgData, messageToEdit, {
serverId: targetMsgData.serverId,
guildId: targetMsgData.guildId,
user: interaction.user,
imageURLs,
});

// find all the messages through the network
const broadcastedMsgs = Object.values(await getBroadcasts(target.id, targetMsgData.hubId));
const channelSettingsArr = await db.connectedList.findMany({
where: { channelId: { in: targetMsgData.broadcastMsgs.map((c) => c.channelId) } },
where: { channelId: { in: broadcastedMsgs.map((c) => c.channelId) } },
});

const results = targetMsgData.broadcastMsgs.map(async (msg) => {
const results = broadcastedMsgs.map(async (msg) => {
const connection = channelSettingsArr.find((c) => c.channelId === msg.channelId);
if (!connection) return false;

Expand Down Expand Up @@ -232,9 +221,9 @@ export default class EditMessage extends BaseCommand {

private async buildEmbeds(
target: Message,
targetMsgData: originalMessages,
targetMsgData: OriginalMessage,
messageToEdit: string,
opts: { user: User; serverId: string; imageURLs?: ImageUrls },
opts: { user: User; guildId: string; imageURLs?: ImageUrls },
) {
let embedContent = messageToEdit;
let embedImage = null;
Expand All @@ -257,7 +246,7 @@ export default class EditMessage extends BaseCommand {
embed = EmbedBuilder.from(target.embeds[0]).setDescription(embedContent).setImage(embedImage);
}
else {
const guild = await target.client.fetchGuild(opts.serverId);
const guild = await target.client.fetchGuild(opts.guildId);

// create a new embed if the message being edited is in compact mode
embed = new EmbedBuilder()
Expand Down
Loading
Loading