const path = require("path"); const Embed = require(path.join(__dirname, "../functions/embed")); const PollDB = require(path.join(__dirname, "../models/polls")); const Giveaways = require(path.join(__dirname, "../models/giveaways")); // Constants const EMOJIS = [ { name: "1️⃣", id: 0 }, { name: "2️⃣", id: 1 }, { name: "3️⃣", id: 2 }, { name: "4️⃣", id: 3 }, { name: "5️⃣", id: 4 }, { name: "6️⃣", id: 5 }, { name: "7️⃣", id: 6 }, { name: "8️⃣", id: 7 }, { name: "9️⃣", id: 8 }, { name: "🔟", id: 9 }, { name: "🛑", id: "stop" } ]; const COLORS_REGEX = /^([A-Z0-9]+)/; /** * Handles message collector reactions * @param {Object} client - The client instance * @param {Object} message - The message object * @param {string} userId - The user ID * @param {string} emojiId - The emoji ID * @param {Object} collector - The message collector * @returns {Promise} */ async function handleMessageCollector(client, message, userId, emojiId, collector) { if (emojiId === client.config.emojis.check) { if (collector.roles.length === 0) { const db = await client.database.getGuild(message.server.id); await Promise.all([ message.delete().catch(() => {}), client.messages.get(collector?.oldMessageId)?.delete().catch(() => {}) ]); const reactions = [...collector.rolesDone.map(e => e.emoji)]; const content = collector.type === "content" ? { content: `${message.content}\n\n##### ${client.translate.get(db.language, "Events.messageReactionAdd.cooldown")}`, interactions: [reactions] } : { embeds: [new Embed().setColor("#A52F05").setDescription(`${client.messages.get(message.id).embeds[0].description}\n\n##### ${client.translate.get(db.language, "Events.messageReactionAdd.cooldown")}`)], interactions: [reactions] }; const msg = await message.channel.sendMessage(content); db.roles.push({ msgId: msg.id, chanId: msg.channelId, roles: [...collector.rolesDone] }); await client.database.updateGuild(msg.server.id, { roles: db.roles }); clearTimeout(client.messageCollector.get(userId).timeout); return client.messageCollector.delete(userId); } return; } if (emojiId === client.config.emojis.cross) { const db = await client.database.getGuild(message.server.id); client.messageCollector.delete(userId); return message.reply({ embeds: [new Embed().setColor("#A52F05").setDescription(client.translate.get(db.language, "Events.messageReactionAdd.deleteCollector"))] }); } if (collector.roles.length === 0) return; const emote = COLORS_REGEX.test(emojiId) ? `:${emojiId}:` : emojiId; const role = collector.roles[0]; const roleColor = role[1].colour?.includes("linear-gradient") ? '#000000' : role[1].colour; collector.rolesDone.push({ emoji: emojiId, role: role[0], name: role[1].name, color: roleColor }); const content = collector.type === "content" ? { content: message.content.replace(`{role:${collector.regex[0]}}`, `${emote} $\\text{\\textcolor{${roleColor}}{${role[1].name}}}$`) } : { embeds: [new Embed().setColor("#A52F05").setDescription(client.messages.get(message.id).embeds[0].description.replace(`{role:${collector.regex[0]}}`, `:${emojiId}: $\\text{\\textcolor{${roleColor}}{${role[1].name}}}$`))] }; await message.edit(content); collector.roles.shift(); return collector.regex.shift(); } /** * Handles pagination reactions * @param {Object} client - The client instance * @param {Object} message - The message object * @param {Object} paginateCheck - The pagination check object * @param {string} emojiId - The emoji ID * @returns {Promise} */ async function handlePagination(client, message, paginateCheck, emojiId) { const { pages, page } = paginateCheck; let newPage = page; switch (emojiId) { case "⏪": if (page !== 0) { await message.edit({ embeds: [pages[0]] }).catch(() => {}); newPage = 0; } break; case "⬅️": if (pages[page - 1]) { await message.edit({ embeds: [pages[--newPage]] }).catch(() => {}); } break; case "➡️": if (pages[page + 1]) { await message.edit({ embeds: [pages[++newPage]] }).catch(() => {}); } break; case "⏩": if (page !== pages.length) { await message.edit({ embeds: [pages[pages.length - 1]] }).catch(() => {}); newPage = pages.length - 1; } break; } if (newPage !== page) { paginateCheck.page = newPage; } } /** * Handles poll reactions * @param {Object} client - The client instance * @param {Object} message - The message object * @param {Object} pollCheck - The poll check object * @param {string} userId - The user ID * @param {string} emojiId - The emoji ID * @returns {Promise} */ async function handlePoll(client, message, pollCheck, userId, emojiId) { const convert = EMOJIS.findIndex(e => e.name === emojiId); if (convert === 10 && pollCheck.owner === userId) { await PollDB.findOneAndDelete({ messageId: message.id }); await pollCheck.poll.update(); const tooMuch = []; if (pollCheck.poll.options.description.length > 80) { tooMuch.push(`**${client.translate.get(pollCheck.lang, "Events.messageReactionAdd.title")}**: ${pollCheck.poll.options.description}`); } pollCheck.poll.voteOptions.name.filter(e => e).forEach((e, i) => { if (e.length > 70) { tooMuch.push(`**${i + 1}.** ${e}`); } }); await message.edit({ content: `${client.translate.get(pollCheck.lang, "Events.messageReactionAdd.owner")} (<@${pollCheck.owner}>) ${client.translate.get(pollCheck.lang, "Events.messageReactionAdd.end")}:`, embeds: [new Embed() .setDescription(tooMuch.length > 0 ? tooMuch.join("\n") : null) .setMedia(await client.Uploader.upload(pollCheck.poll.canvas.toBuffer(), `Poll.png`)) .setColor("#F24646")] }).catch(() => {}); return client.polls.delete(message.id); } if (convert === 0 || (convert !== -1 && convert !== 10)) { if (client.reactions.get(userId)) { return client.users.get(userId)?.openDM() .then(dm => dm.sendMessage(client.translate.get(pollCheck.lang, "Events.messageReactionAdd.tooFast"))) .catch(() => {}); } if (pollCheck.users.includes(userId)) return; pollCheck.users.push(userId); const user = client.users.get(userId) || await client.users.fetch(userId); await pollCheck.poll.addVote(convert, userId, 'https://chat.f95.io/api/users/01HATCWS7XZ7KEHW64AV20SMKR/default_avatar', message.id); const tooMuch = []; if (pollCheck.poll.options.description.length > 80) { tooMuch.push(`**${client.translate.get(pollCheck.lang, "Events.messageReactionAdd.title")}**: ${pollCheck.poll.options.description}`); } pollCheck.poll.voteOptions.name.filter(e => e).forEach((e, i) => { if (e.length > 70) { tooMuch.push(`**${i + 1}.** ${e}`); } }); await message.edit({ embeds: [new Embed() .setDescription(tooMuch.length > 0 ? tooMuch.join("\n") : null) .setMedia(await client.Uploader.upload(pollCheck.poll.canvas.toBuffer(), `Poll.png`)) .setColor("#A52F05")] }).catch(() => {}); client.reactions.set(userId, Date.now() + 3000); setTimeout(() => client.reactions.delete(userId), 3000); } } /** * Handles giveaway reactions * @param {Object} client - The client instance * @param {Object} message - The message object * @param {Object} db - The giveaway database object * @param {string} userId - The user ID * @param {string} emojiId - The emoji ID * @returns {Promise} */ async function handleGiveaway(client, message, db, userId, emojiId) { if (emojiId === client.config.emojis.confetti && !db.ended) { if (client.reactions.get(userId) || db.users.find(u => u.userID === userId)) return; db.users.push({ userID: userId }); db.picking.push({ userID: userId }); await db.save(); client.reactions.set(userId, Date.now() + 3000); setTimeout(() => client.reactions.delete(userId), 3000); await client.users.get(userId)?.openDM() .then(dm => dm.sendMessage( `${client.translate.get(db.lang, "Events.messageReactionAdd.joined")} [${db.prize}](https://chat.f95.io/server/${db.serverId}/channel/${db.channelId}/${db.messageId})!\n` + `${client.translate.get(db.lang, "Events.messageReactionAdd.joined2")} **${db.users.length}** ${client.translate.get(db.lang, "Events.messageReactionAdd.joined3")}` )) .catch(() => {}); } else if (emojiId === client.config.emojis.stop && db.owner === userId && !db.ended) { const endDate = Date.now(); if (db.users.length === 0) { const noUsers = new Embed() .setColor("#A52F05") .setTitle(client.translate.get(db.lang, "Events.messageReactionAdd.giveaway")) .setDescription( `${client.translate.get(db.lang, "Events.messageReactionAdd.owner")} (<@${userId}>) ${client.translate.get(db.lang, "Events.messageReactionAdd.early")}\n` + `${client.translate.get(db.lang, "Events.messageReactionAdd.endNone")}!\n\n` + `${client.translate.get(db.lang, "Events.messageReactionAdd.ended")}: \n` + `${client.translate.get(db.lang, "Events.messageReactionAdd.prize")}: ${db.prize}\n` + `${client.translate.get(db.lang, "Events.messageReactionAdd.winnersNone")}` + (db.requirement ? `\n${client.translate.get(db.lang, "Events.messageReactionAdd.reqs")}: ${db.requirement}` : ``) ); await db.updateOne({ ended: true, endDate }); await db.save(); return await client.api.patch(`/channels/${db.channelId}/messages/${db.messageId}`, { embeds: [noUsers] }); } for (let i = 0; i < db.winners; i++) { const winner = db.picking[Math.floor(Math.random() * db.picking.length)]; if (winner) { db.picking = db.picking.filter(object => object.userID !== winner.userID); db.pickedWinners.push({ id: winner.userID }); } } await db.updateOne({ ended: true, endDate }); await db.save(); const noUsers = new Embed() .setColor("#A52F05") .setTitle(client.translate.get(db.lang, "Events.messageReactionAdd.giveaway")) .setDescription( `${client.translate.get(db.lang, "Events.messageReactionAdd.owner")} (<@${userId}>) ${client.translate.get(db.lang, "Events.messageReactionAdd.early")}\n` + `${client.translate.get(db.lang, "Events.messageReactionAdd.partici")}: ${db.users.length}\n\n` + `${client.translate.get(db.lang, "Events.messageReactionAdd.ended")}: \n` + `${client.translate.get(db.lang, "Events.messageReactionAdd.prize")}: ${db.prize}\n` + `${client.translate.get(db.lang, "Events.messageReactionAdd.winners")}: ${db.pickedWinners.length > 0 ? db.pickedWinners.map(w => `<@${w.id}>`).join(", ") : client.translate.get(db.lang, "Events.messageReactionAdd.none")}` + (db.requirement ? `\n${client.translate.get(db.lang, "Events.messageReactionAdd.reqs")}: ${db.requirement}` : ``) ); await message.edit({ embeds: [noUsers] }).catch(() => {}); await client.api.post(`/channels/${db.channelId}/messages`, { content: `${client.translate.get(db.lang, "Events.messageReactionAdd.congrats")} ${db.pickedWinners.map(w => `<@${w.id}>`).join(", ")}! ${client.translate.get(db.lang, "Events.messageReactionAdd.youWon")} **[${db.prize}](https://chat.f95.io/server/${db.serverId}/channel/${db.channelId}/${db.messageId})**!` }).catch(() => {}); client.reactions.set(userId, Date.now() + 3000); setTimeout(() => client.reactions.delete(userId), 3000); } } /** * Handles role reactions * @param {Object} client - The client instance * @param {Object} message - The message object * @param {Object} db - The guild database object * @param {string} userId - The user ID * @param {string} emojiId - The emoji ID * @returns {Promise} */ async function handleRoleReaction(client, message, db, userId, emojiId) { if (client.reactions.get(userId)) return; const roles = []; db.roles.find(e => e.msgId === message.id).roles.map(e => roles.push(e)); const role = roles.find(e => e.emoji === emojiId); const member = await (client.servers.get(message.server.id) || await client.servers.fetch(message.server.id))?.fetchMember(userId); if (!member) return; let error = false; let dataRoles = []; if (member.roles) member.roles.map(e => dataRoles.push(e)); if (dataRoles.includes(role.role)) return; client.reactions.set(userId, Date.now() + 3000); setTimeout(() => client.reactions.delete(userId), 3000); dataRoles.push(role.role); await member.edit({ roles: dataRoles }).catch(() => { error = true }); if (db.dm) { const dmMessage = error ? client.translate.get(db.language, "Events.messageReactionAdd.noPerms").replace("{role}", `**${role.name}**`) : client.translate.get(db.language, "Events.messageReactionAdd.success").replace("{role}", `**${role.name}**`); await member?.user?.openDM() .then(dm => dm.sendMessage(dmMessage)) .catch(() => {}); } } /** * Main event handler for message reactions * @param {Object} client - The client instance * @param {Object} message - The message object * @param {string} userId - The user ID * @param {string} emojiId - The emoji ID * @returns {Promise} */ module.exports = async (client, message, userId, emojiId) => { try { const paginateCheck = client.paginate.get(userId); const pollCheck = client.polls.get(message.id); const collector = client.messageCollector.get(userId); const editCollector = client.messageEdit.get(userId); // Handle message collector if (collector && (collector.messageId === message.id || (collector?.oldMessageId === message.id && collector.channelId === message.channelId))) { return await handleMessageCollector(client, message, userId, emojiId, collector); } // Handle edit collector if (editCollector && (editCollector.messageId === message.id || (editCollector?.botMessage === message.id && editCollector.channelId === message.channelId))) { return await handleMessageCollector(client, message, userId, emojiId, editCollector); } // Handle pagination if (paginateCheck && paginateCheck.message === message.id) { return await handlePagination(client, message, paginateCheck, emojiId); } // Handle poll if (pollCheck) { return await handlePoll(client, message, pollCheck, userId, emojiId); } // Handle giveaway const giveaway = await Giveaways.findOne({ messageId: message.id }); if (giveaway) { return await handleGiveaway(client, message, giveaway, userId, emojiId); } // Handle role reaction const db = await client.database.getGuild(message.server.id, true); if (db?.roles.find(e => e.msgId === message.id)?.roles.find(e => e.emoji === emojiId)) { return await handleRoleReaction(client, message, db, userId, emojiId); } } catch (error) { console.error('Error in messageReactionAdd:', error); } };