const { sanitizeDiscordAuthor } = require("../utils/sanitize"); const axios = require("axios"); const { shardMG } = require("../shard"); const { localMessages, getTrialLeftTimeAndSubStatus, } = require("../utils/common"); const { SettingsService } = require("../service/SettingsService"); const { toBoolean } = require("../utils/toBoolean"); const { getWebhookAvatar } = require("../utils/discordHelpers"); class Recipient { constructor(email, connect) { this.email = email; this.connect = connect; } async forwardEmail(inbox) { const files = []; let totalSize = 0; const content = inbox.getTruncatedContents(); totalSize += Buffer.byteLength(content, "utf8"); const locale = localMessages(); if (inbox.isEmailContainsAttachments()) { const attachments = inbox.getAttachments(); const attachmentsCount = attachments.length <= 10 ? attachments.length : 10; // Max attachments per webhook for (let i = 0; i < attachmentsCount; i++) { const attachment = attachments[i]; if ( attachment.content && attachment.content.type === "Buffer" && Array.isArray(attachment.content.data) ) { const bufferData = Buffer.from(attachment.content.data); files.push({ attachment: bufferData, name: attachment.filename, }); totalSize += bufferData.length; } else if (Buffer.isBuffer(attachment.content)) { files.push({ attachment: attachment.content, name: attachment.filename, }); totalSize += attachment.content.length; } else { console.error( "Unknown attachment content format:", attachment.content ); } } } let attachUrl = null; const settings = await SettingsService.getAllSettings(this.connect.id); if ( inbox.isContentRequiresConversion() || inbox.isContentRequiresTruncation() || inbox.isAttachmentHasFiles() ) { try { if ( settings.preview_mode === undefined || toBoolean(settings.preview_mode) ) { const { data: buffer } = await axios.get( `${inbox.getFrontPreviewUrl()}`, { responseType: "arraybuffer", } ); if ( buffer && buffer.type === "Buffer" && Array.isArray(buffer.data) ) { const bufferData = Buffer.from(buffer.data); files.push({ attachment: bufferData, name: `${inbox.getId()}.png`, }); totalSize += bufferData.length; attachUrl = `attachment://${inbox.getId()}.png`; } else if (Buffer.isBuffer(buffer)) { files.push({ attachment: buffer, name: `${inbox.getId()}.png`, }); totalSize += buffer.length; attachUrl = `attachment://${inbox.getId()}.png`; } else { console.error("Unknown attachment content format:", buffer); } } } catch (error) { console.error(`Failed to generate email preview - ${error.message}`); } } let components = []; if (settings.web_mode === undefined || toBoolean(settings.web_mode)) { components.push({ type: 2, // TYPE BUTTON label: "Open", style: 5, // STYLE LINK url: inbox.getPreviewUrl(), }); } if (settings.reply_mode === undefined || toBoolean(settings.reply_mode)) { components.push({ type: 2, // TYPE BUTTON label: "Reply", style: 5, // STYLE LINK url: inbox.getReplyLink(this.connect), }); } const data = await getTrialLeftTimeAndSubStatus(this.connect.guild_id); let embeds = []; let embed = {}; if (!data?.subscription_status && data?.days_remaining >= 0) { embed.timestamp = inbox.getDate(); } if (attachUrl) { embed.image = { url: attachUrl, }; } if (!data?.subscription_status && data?.days_remaining >= 0) { embed.footer = { text: `Trial ends in ${data?.days_remaining} days`, }; } if (Object.keys(embed).length !== 0) { embeds.push(embed); } const options = { content, username: sanitizeDiscordAuthor(settings.custom_name_edit_text) || sanitizeDiscordAuthor(inbox.getAuthor()) || "_No Author Identified_", avatarUrl: toBoolean(settings.avatar_mode) ? await getWebhookAvatar(this.connect.id) : await inbox.getAvatar(this.connect.id), components: !!components.length ? [ { type: 1, // BUTTON SHOULD BE IN THE ACTION LIST components, }, ] : [], }; if (embeds.length > 0) { options.embeds = embeds; } console.log( "⚠️ Before sendRecipient forwardEmail", this.email, ` - ${new Date() .toLocaleString("sv-SE", { timeZone: "Europe/Kyiv" }) .replace(" ", "T")}` ); await shardMG.broadcastEval( async (client, { options, files, connect, email, locale }) => { const guild = client.guilds.cache.get(connect.guild_id); if (client.shard.ids.includes(guild?.shardId)) { const { WebhookClient, PermissionsBitField } = require("discord.js"); const path = require("path"); const { report } = require(path.resolve( __dirname, "../../../../utils/sentry" )); const { deleteConnectFromChannel } = require(path.resolve( __dirname, "../../../../utils/connects" )); const { isWebhookExists } = require(path.resolve( __dirname, "../../../../utils/webhooks" )); const { refreshWebhook } = require(path.resolve( __dirname, "../../../../utils/discordHelpers/refreshWebhook" )); const { checkIsEntityToLarge } = require(path.resolve( __dirname, "../../../../utils/discordHelpers/checkDsEntitySize" )); const { checkClientPermissions } = require(path.resolve( __dirname, "../../../../utils/discordHelpers" )); const { sendNotifyAboutPermission } = require(path.resolve( __dirname, "../../../../utils/discordHelpers/sendNotifyAboutPermission" )); const { NotificationEventService } = require(path.resolve( __dirname, "../../../../service" )); const guildBoostLevel = guild?.premiumTier; if ( await checkIsEntityToLarge(files, options.content, guildBoostLevel) ) { console.log("Error: The message size exceeds Discord's limit."); files.length = 0; } try { if (!(await isWebhookExists(connect.webhook_id))) { if ( await checkClientPermissions( client, connect.guild_id, PermissionsBitField.Flags.ManageWebhooks ) ) { await sendNotifyAboutPermission({ dsClient: client, guildId: connect.guild_id, userId: connect.user_id, content: locale.msg.channel_permissions_is_incorrect.replace( "{guild_link}", `[${ guild.name || "Unknown" }](https://discord.com/channels/${guild.id})` ), }); return; } else { await NotificationEventService.delNotification( connect.guild_id, "perm" ); } connect = await refreshWebhook(email, client); if (!connect) { console.error(`Failed to refresh webhook for email: ${email}`); return; } } const webhookClient = new WebhookClient({ id: connect.webhook_id, token: connect.webhook_token, }); await webhookClient.send({ ...options, files: files.map((item) => ({ attachment: Buffer.from(item.attachment.data), name: item.name, })), threadId: Boolean(connect.is_thread) ? connect.channel_id : null, }); console.log( "⚠️ SendRecipient forwardEmail", email, ` - ${new Date() .toLocaleString("sv-SE", { timeZone: "Europe/Kyiv" }) .replace(" ", "T")}` ); } catch (error) { if (error.response && error.response?.data?.code === 10015) { await deleteConnectFromChannel(connect.channel_id); report( error, `Failed forward an email to webhook ID ${connect.webhook_id}. The connect was deleted.` ); } else if (error.code === 50001) { report( error, `Failed forward an email to webhook ID ${connect.webhook_id}. Missing access to the channel.` ); } else { report( error, `Failed forward an email to webhook ID ${connect.webhook_id}` ); } } } }, { context: { options, files, connect: this.connect, email: this.email, locale, }, } ); } } module.exports = Recipient;