Compare commits
No commits in common. "2d0a6626a878671a89d8ac4790eda15a47f700f4" and "ddd5972f723050995ab676fed0ebce996234fd06" have entirely different histories.
2d0a6626a8
...
ddd5972f72
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
@ -7,8 +7,6 @@ module.exports = {
|
|||||||
cooldown: 5000,
|
cooldown: 5000,
|
||||||
available: true,
|
available: true,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
aliases: ['av']
|
aliases: ['av']
|
||||||
},
|
},
|
||||||
run: async (client, message, args, db) => {
|
run: async (client, message, args, db) => {
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
const Embed = require("../functions/embed")
|
const Embed = require("../functions/embed")
|
||||||
const Uploader = require("revolt-uploader");
|
// const { } = require('revolt.js')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
config: {
|
config: {
|
||||||
@ -10,90 +8,33 @@ module.exports = {
|
|||||||
cooldown: 5000,
|
cooldown: 5000,
|
||||||
available: true,
|
available: true,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
aliases: ['gd']
|
aliases: ['gd']
|
||||||
},
|
},
|
||||||
run: async (client, message, args, db) => {
|
run: async (client, message, args, db) => {
|
||||||
try {
|
|
||||||
|
|
||||||
function randomInteger(min, max) {
|
function randomInteger(min, max) {
|
||||||
min = Math.ceil(min);
|
min = Math.ceil(min);
|
||||||
max = Math.floor(max);
|
max = Math.floor(max);
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
let targetUser;
|
const member = await (client.servers.get(message.server.id) || await client.servers.fetch(message.server.id))?.fetchMember(message.mentionIds[0]).then((user) => {
|
||||||
|
return console.log();
|
||||||
// Check if there's a mentioned user
|
|
||||||
if (message.mentionIds && message.mentionIds.length > 0) {
|
|
||||||
try {
|
|
||||||
const server = await client.servers.fetch(message.server.id);
|
|
||||||
const member = await server.fetchMember(message.mentionIds[0]);
|
|
||||||
|
|
||||||
if (!member || !member.id || !member.id.user) {
|
|
||||||
throw new Error("Invalid member structure");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the user using the user ID from the member object
|
|
||||||
targetUser = await client.users.fetch(member.id.user);
|
|
||||||
|
|
||||||
if (!targetUser || !targetUser.username) {
|
|
||||||
throw new Error("Could not fetch user information");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (fetchError) {
|
|
||||||
console.error("Fetch error details:", fetchError.message);
|
|
||||||
return message.reply({
|
|
||||||
embeds: [new Embed()
|
|
||||||
.setDescription("Could not find the mentioned user.")
|
|
||||||
.setColor(`#FF0000`)]
|
|
||||||
}, false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Use the command author if no user is mentioned
|
|
||||||
targetUser = message.author;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!targetUser) {
|
|
||||||
return message.reply({
|
|
||||||
embeds: [new Embed()
|
|
||||||
.setDescription("Could not determine the target user.")
|
|
||||||
.setColor(`#FF0000`)]
|
|
||||||
}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const amount = randomInteger(1, 100);
|
|
||||||
const imagePath = path.join(__dirname, "../assets/gaydar.jpg");
|
|
||||||
|
|
||||||
// Check if file exists
|
|
||||||
if (!fs.existsSync(imagePath)) {
|
|
||||||
return message.reply({
|
|
||||||
embeds: [new Embed()
|
|
||||||
.setDescription("Error: Required image file not found.")
|
|
||||||
.setColor(`#FF0000`)]
|
|
||||||
}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload the image as an attachment
|
|
||||||
const attachment = await client.Uploader.uploadFile(imagePath, "gaydar.jpg");
|
|
||||||
|
|
||||||
// Send the message with the attachment
|
|
||||||
await message.channel.sendMessage({
|
|
||||||
content: `#### ${targetUser.username} is ${amount}% gay.`,
|
|
||||||
attachments: [attachment]
|
|
||||||
});
|
});
|
||||||
|
// const target = member.user.username;
|
||||||
|
// return console.log(member)
|
||||||
|
// let amount = randomInteger(1, 100);
|
||||||
|
|
||||||
} catch (error) {
|
// const embed = {
|
||||||
console.log(`${Date(Date.now().toString()).slice(0, 25)}`);
|
// description: `#### ${target} is ${amount}% gay.`,
|
||||||
console.log("User: " + message.author.username + ` [${message.authorId}] ` + " | Command: gaydar | Args: " + (args?.join(" ") || "NONE"));
|
// colour: "#ff8080",
|
||||||
console.log(error.message);
|
// image: 'https://overlord.lordainz.xyz/f/gaydar.jpg'
|
||||||
|
// }
|
||||||
|
|
||||||
return message.reply({
|
// await message.channel.sendMessage({ content: "", embeds: [embed] }).catch(err => {
|
||||||
embeds: [new Embed()
|
// console.log(`${Date(Date.now().toString()).slice(0, 25)}`);
|
||||||
.setDescription("An error occurred while processing the command.")
|
// console.log("User: " + message.author.username + ` [${message.authorId}] ` + " | Command: gardar | Args: " + (args?.join(" ") || "NONE"))
|
||||||
.setColor(`#FF0000`)]
|
// console.log(err.message);
|
||||||
}, false);
|
// return;
|
||||||
}
|
// });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -9,8 +9,6 @@ module.exports = {
|
|||||||
cooldown: 5000,
|
cooldown: 5000,
|
||||||
available: true,
|
available: true,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
aliases: ['tenor', 'giphy', 'gify']
|
aliases: ['tenor', 'giphy', 'gify']
|
||||||
},
|
},
|
||||||
run: async (client, message, args, db) => {
|
run: async (client, message, args, db) => {
|
||||||
|
|||||||
@ -7,8 +7,6 @@ module.exports = {
|
|||||||
cooldown: 5000,
|
cooldown: 5000,
|
||||||
available: true,
|
available: true,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
aliases: ['h']
|
aliases: ['h']
|
||||||
},
|
},
|
||||||
run: async (client, message, args, db) => {
|
run: async (client, message, args, db) => {
|
||||||
|
|||||||
@ -9,8 +9,6 @@ module.exports = {
|
|||||||
cooldown: 10000,
|
cooldown: 10000,
|
||||||
available: true,
|
available: true,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
aliases: ["stats"]
|
aliases: ["stats"]
|
||||||
},
|
},
|
||||||
run: async (client, message, args, db) => {
|
run: async (client, message, args, db) => {
|
||||||
|
|||||||
@ -11,8 +11,6 @@ module.exports = {
|
|||||||
cooldown: 10000,
|
cooldown: 10000,
|
||||||
available: true,
|
available: true,
|
||||||
permissions: ['ManageServer'],
|
permissions: ['ManageServer'],
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
aliases: ["poll"]
|
aliases: ["poll"]
|
||||||
},
|
},
|
||||||
run: async (client, message, args, db) => {
|
run: async (client, message, args, db) => {
|
||||||
|
|||||||
@ -7,9 +7,7 @@ module.exports = {
|
|||||||
available: true,
|
available: true,
|
||||||
usage: true,
|
usage: true,
|
||||||
permissions: ["ManageServer"],
|
permissions: ["ManageServer"],
|
||||||
aliases: [],
|
aliases: []
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
},
|
},
|
||||||
run: async (client, message, args, db) => {
|
run: async (client, message, args, db) => {
|
||||||
const embed = new Embed()
|
const embed = new Embed()
|
||||||
|
|||||||
@ -5,9 +5,7 @@ module.exports = {
|
|||||||
cooldown: 0,
|
cooldown: 0,
|
||||||
available: "Owner",
|
available: "Owner",
|
||||||
permissions: [],
|
permissions: [],
|
||||||
aliases: ["r"],
|
aliases: ["r"]
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
},
|
},
|
||||||
run: async (client, message, args) => {
|
run: async (client, message, args) => {
|
||||||
if (!client.config.owners.includes(message.authorId)) return;
|
if (!client.config.owners.includes(message.authorId)) return;
|
||||||
|
|||||||
@ -11,8 +11,6 @@ module.exports = {
|
|||||||
cooldown: 10000,
|
cooldown: 10000,
|
||||||
available: true,
|
available: true,
|
||||||
permissions: ['ManageServer'],
|
permissions: ['ManageServer'],
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
aliases: ["r7"]
|
aliases: ["r7"]
|
||||||
},
|
},
|
||||||
run: async (client, message, args, db) => {
|
run: async (client, message, args, db) => {
|
||||||
|
|||||||
@ -8,9 +8,7 @@ module.exports = {
|
|||||||
cooldown: 5000,
|
cooldown: 5000,
|
||||||
available: true,
|
available: true,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
aliases: ['ub'],
|
aliases: ['ub']
|
||||||
roles: [],
|
|
||||||
dm: false,
|
|
||||||
},
|
},
|
||||||
run: async (client, message, args, db) => {
|
run: async (client, message, args, db) => {
|
||||||
let query = args.join(' ');
|
let query = args.join(' ');
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
const path = require("path");
|
const Embed = require("../functions/embed");
|
||||||
const Embed = require(path.join(__dirname, "../functions/embed"));
|
const Collector = require("../functions/messageCollector");
|
||||||
const Collector = require(path.join(__dirname, "../functions/messageCollector"));
|
const EditCollector = require("../functions/messageEdit");
|
||||||
const EditCollector = require(path.join(__dirname, "../functions/messageEdit"));
|
const CommandDB = require('../models/commands');
|
||||||
const CommandDB = require(path.join(__dirname, "../models/commands"));
|
const { isJson } = require('../functions/randomStr');
|
||||||
const { isJson } = require(path.join(__dirname, "../functions/randomStr"));
|
const logger = require('../functions/logger');
|
||||||
|
const audit = require('../functions/audit');
|
||||||
|
|
||||||
module.exports = async (client, message) => {
|
module.exports = async (client, message) => {
|
||||||
// Early return checks
|
// Early return checks
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
const path = require("path");
|
const PollDB = require("../models/polls");
|
||||||
const PollDB = require(path.join(__dirname, "../models/polls"));
|
const Giveaways = require("../models/giveaways");
|
||||||
const Giveaways = require(path.join(__dirname, "../models/giveaways"));
|
const GuildDB = require("../models/guilds");
|
||||||
const GuildDB = require(path.join(__dirname, "../models/guilds"));
|
|
||||||
module.exports = async (client, msg) => {
|
module.exports = async (client, msg) => {
|
||||||
const paginateCheck = client.paginate.get(msg.authorId);
|
const paginateCheck = client.paginate.get(msg.authorId);
|
||||||
const pollCheck = client.polls.get(msg.id);
|
const pollCheck = client.polls.get(msg.id);
|
||||||
|
|||||||
@ -1,290 +1,200 @@
|
|||||||
const path = require("path");
|
const Embed = require("../functions/embed");
|
||||||
const Embed = require(path.join(__dirname, "../functions/embed"));
|
const PollDB = require("../models/polls");
|
||||||
const PollDB = require(path.join(__dirname, "../models/polls"));
|
const Giveaways = require("../models/giveaways");
|
||||||
const Giveaways = require(path.join(__dirname, "../models/giveaways"));
|
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 = /^([A-Z0-9]+)/;
|
||||||
|
|
||||||
// Constants
|
module.exports = async (client, message, userId, emojiId) => {
|
||||||
const EMOJIS = [
|
const paginateCheck = client.paginate.get(userId);
|
||||||
{ name: "1️⃣", id: 0 }, { name: "2️⃣", id: 1 }, { name: "3️⃣", id: 2 },
|
const pollCheck = client.polls.get(message.id);
|
||||||
{ name: "4️⃣", id: 3 }, { name: "5️⃣", id: 4 }, { name: "6️⃣", id: 5 },
|
const collector = client.messageCollector.get(userId);
|
||||||
{ name: "7️⃣", id: 6 }, { name: "8️⃣", id: 7 }, { name: "9️⃣", id: 8 },
|
const editCollector = client.messageEdit.get(userId);
|
||||||
{ name: "🔟", id: 9 }, { name: "🛑", id: "stop" }
|
|
||||||
];
|
|
||||||
const COLORS_REGEX = /^([A-Z0-9]+)/;
|
|
||||||
|
|
||||||
/**
|
if (collector && collector.messageId === message.id || collector?.oldMessageId && collector?.oldMessageId === message.id && collector.channelId === message.channelId) {
|
||||||
* 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<void>}
|
|
||||||
*/
|
|
||||||
async function handleMessageCollector(client, message, userId, emojiId, collector) {
|
|
||||||
if (emojiId === client.config.emojis.check) {
|
if (emojiId === client.config.emojis.check) {
|
||||||
if (collector.roles.length === 0) {
|
if (collector.roles.length === 0) {
|
||||||
const db = await client.database.getGuild(message.server.id);
|
const db = await client.database.getGuild(message.server.id);
|
||||||
await Promise.all([
|
message.delete().catch(() => { });
|
||||||
message.delete().catch(() => {}),
|
client.messages.get(collector?.oldMessageId)?.delete().catch(() => { })
|
||||||
client.messages.get(collector?.oldMessageId)?.delete().catch(() => {})
|
|
||||||
]);
|
|
||||||
|
|
||||||
const reactions = [...collector.rolesDone.map(e => e.emoji)];
|
const reactions = [...collector.rolesDone.map(e => e.emoji)];
|
||||||
const content = collector.type === "content"
|
message.channel.sendMessage(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] }).then(async (msg) => {
|
||||||
? { 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] });
|
db.roles.push({ msgId: msg.id, chanId: msg.channelId, roles: [...collector.rolesDone] });
|
||||||
await client.database.updateGuild(msg.server.id, { roles: db.roles });
|
await client.database.updateGuild(msg.server.id, { roles: db.roles });
|
||||||
|
});
|
||||||
|
|
||||||
clearTimeout(client.messageCollector.get(userId).timeout);
|
clearTimeout(client.messageCollector.get(userId).timeout);
|
||||||
return client.messageCollector.delete(userId);
|
return client.messageCollector.delete(userId);
|
||||||
}
|
} else return;
|
||||||
return;
|
} else if (emojiId === client.config.emojis.cross) {
|
||||||
}
|
|
||||||
|
|
||||||
if (emojiId === client.config.emojis.cross) {
|
|
||||||
const db = await client.database.getGuild(message.server.id);
|
const db = await client.database.getGuild(message.server.id);
|
||||||
client.messageCollector.delete(userId);
|
client.messageCollector.delete(userId);
|
||||||
return message.reply({
|
return message.reply({ embeds: [new Embed().setColor("#A52F05").setDescription(client.translate.get(db.language, "Events.messageReactionAdd.deleteCollector"))] },);
|
||||||
embeds: [new Embed().setColor("#A52F05").setDescription(client.translate.get(db.language, "Events.messageReactionAdd.deleteCollector"))]
|
} else {
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collector.roles.length === 0) return;
|
if (collector.roles.length === 0) return;
|
||||||
|
let emote;
|
||||||
const emote = COLORS_REGEX.test(emojiId) ? `:${emojiId}:` : emojiId;
|
if (colors.test(emojiId)) emote = `:${emojiId}:`;
|
||||||
const role = collector.roles[0];
|
else if (!colors.test(emojiId)) emote = emojiId
|
||||||
const roleColor = role[1].colour?.includes("linear-gradient") ? '#000000' : role[1].colour;
|
collector.rolesDone.push({ emoji: emojiId, role: collector.roles[0][0], name: collector.roles[0][1].name, color: collector.roles[0][1].colour?.includes("linear-gradient") ? '#000000' : collector.roles[0][1].colour });
|
||||||
|
message.edit(collector.type === "content" ? { content: message.content.replace(`{role:${collector.regex[0]}}`, `${emote} $\\text{\\textcolor{${collector.roles[0][1].colour?.includes("linear-gradient") ? '#000000' : collector.roles[0][1].colour}}{${collector.roles[0][1].name}}}$`) } : { embeds: [new Embed().setColor("#A52F05").setDescription(client.messages.get(message.id).embeds[0].description.replace(`{role:${collector.regex[0]}}`, `:${emojiId}: $\\text{\\textcolor{${collector.roles[0][1].colour?.includes("linear-gradient") ? '#000000' : collector.roles[0][1].colour}}{${collector.roles[0][1].name}}}$`))] })
|
||||||
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();
|
collector.roles.shift();
|
||||||
return collector.regex.shift();
|
return collector.regex.shift();
|
||||||
}
|
}
|
||||||
|
} else if (editCollector && editCollector.messageId === message.id || editCollector?.botMessage && editCollector?.botMessage === message.id && editCollector.channelId === message.channelId) {
|
||||||
/**
|
if (emojiId === client.config.emojis.check) {
|
||||||
* Handles pagination reactions
|
if (editCollector.roles.length === 0) {
|
||||||
* @param {Object} client - The client instance
|
const db = await client.database.getGuild(message.server.id);
|
||||||
* @param {Object} message - The message object
|
message.delete().catch(() => { });
|
||||||
* @param {Object} paginateCheck - The pagination check object
|
client.messages.get(editCollector?.oldMessageId)?.delete().catch(() => { })
|
||||||
* @param {string} emojiId - The emoji ID
|
client.messages.get(editCollector?.botMessage)?.delete().catch(() => { })
|
||||||
* @returns {Promise<void>}
|
const reactions = [...editCollector.rolesDone.map(e => e.emoji)];
|
||||||
*/
|
message.channel.sendMessage(editCollector.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] }).then(async (msg) => {
|
||||||
async function handlePagination(client, message, paginateCheck, emojiId) {
|
db.roles.push({ msgId: msg.id, chanId: msg.channelId, roles: [...editCollector.rolesDone] });
|
||||||
const { pages, page } = paginateCheck;
|
await client.database.updateGuild(msg.server.id, { roles: db.roles.filter(e => e.msgId !== editCollector.oldMessageId) });
|
||||||
let newPage = page;
|
});
|
||||||
|
|
||||||
|
clearTimeout(client.messageEdit.get(userId).timeout);
|
||||||
|
return client.messageEdit.delete(userId);
|
||||||
|
} else return;
|
||||||
|
} else if (emojiId === client.config.emojis.cross) {
|
||||||
|
const db = await client.database.getGuild(message.server.id);
|
||||||
|
client.messageEdit.delete(userId);
|
||||||
|
return message.reply({ embeds: [new Embed().setColor("#A52F05").setDescription(client.translate.get(db.language, "Events.messageReactionAdd.deleteCollector"))] },);
|
||||||
|
} else {
|
||||||
|
if (editCollector.roles.length === 0) return;
|
||||||
|
let emote;
|
||||||
|
if (colors.test(emojiId)) emote = `:${emojiId}:`;
|
||||||
|
else if (!colors.test(emojiId)) emote = emojiId
|
||||||
|
editCollector.rolesDone.push({ emoji: emojiId, role: editCollector.roles[0][0], name: editCollector.roles[0][1].name, color: editCollector.roles[0][1].colour?.includes("linear-gradient") ? '#000000' : editCollector.roles[0][1].colour });
|
||||||
|
message.edit(editCollector.type === "content" ? { content: message.content.replace(`{role:${editCollector.regex[0]}}`, `${emote} $\\text{\\textcolor{${editCollector.roles[0][1].colour?.includes("linear-gradient") ? '#000000' : editCollector.roles[0][1].colour}}{${editCollector.roles[0][1].name}}}$`) } : { embeds: [new Embed().setColor("#A52F05").setDescription(client.messages.get(message.id).embeds[0].description.replace(`{role:${editCollector.regex[0]}}`, `:${emojiId}: $\\text{\\textcolor{${editCollector.roles[0][1].colour?.includes("linear-gradient") ? '#000000' : editCollector.roles[0][1].colour}}{${editCollector.roles[0][1].name}}}$`))] })
|
||||||
|
editCollector.roles.shift();
|
||||||
|
return editCollector.regex.shift();
|
||||||
|
}
|
||||||
|
} else if (paginateCheck && paginateCheck.message == message.id) {
|
||||||
|
let pages = paginateCheck.pages;
|
||||||
|
let page = paginateCheck.page;
|
||||||
switch (emojiId) {
|
switch (emojiId) {
|
||||||
case "⏪":
|
case "⏪":
|
||||||
if (page !== 0) {
|
if (page !== 0) {
|
||||||
await message.edit({ embeds: [pages[0]] }).catch(() => {});
|
message.edit({
|
||||||
newPage = 0;
|
embeds: [pages[0]]
|
||||||
|
}).catch(() => { });
|
||||||
|
return paginateCheck.page = 0
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case "⬅️":
|
case "⬅️":
|
||||||
if (pages[page - 1]) {
|
if (pages[page - 1]) {
|
||||||
await message.edit({ embeds: [pages[--newPage]] }).catch(() => {});
|
message.edit({
|
||||||
|
embeds: [pages[--page]]
|
||||||
|
}).catch(() => { });
|
||||||
|
return paginateCheck.page = paginateCheck.page - 1
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case "➡️":
|
case "➡️":
|
||||||
if (pages[page + 1]) {
|
if (pages[page + 1]) {
|
||||||
await message.edit({ embeds: [pages[++newPage]] }).catch(() => {});
|
message.edit({
|
||||||
|
embeds: [pages[++page]]
|
||||||
|
}).catch(() => { });
|
||||||
|
return paginateCheck.page = paginateCheck.page + 1
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case "⏩":
|
case "⏩":
|
||||||
if (page !== pages.length) {
|
if (page !== pages.length) {
|
||||||
await message.edit({ embeds: [pages[pages.length - 1]] }).catch(() => {});
|
message.edit({
|
||||||
newPage = pages.length - 1;
|
embeds: [pages[pages.length - 1]]
|
||||||
|
}).catch(() => { });
|
||||||
|
return paginateCheck.page = pages.length - 1
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} else if (pollCheck) {
|
||||||
if (newPage !== page) {
|
let tooMuch = [];
|
||||||
paginateCheck.page = newPage;
|
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) => {
|
||||||
|
i++
|
||||||
|
if (e.length > 70) {
|
||||||
|
tooMuch.push(`**${i}.** ${e}`)
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<void>}
|
|
||||||
*/
|
|
||||||
async function handlePoll(client, message, pollCheck, userId, emojiId) {
|
|
||||||
const convert = EMOJIS.findIndex(e => e.name === emojiId);
|
|
||||||
|
|
||||||
|
let convert = emojis.findIndex(e => e.name === emojiId);
|
||||||
if (convert === 10 && pollCheck.owner === userId) {
|
if (convert === 10 && pollCheck.owner === userId) {
|
||||||
await PollDB.findOneAndDelete({ messageId: message.id });
|
await PollDB.findOneAndDelete({ messageId: message.id });
|
||||||
await pollCheck.poll.update();
|
await pollCheck.poll.update();
|
||||||
|
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.map(e => e).join("\n") : null).setMedia(await client.Uploader.upload(pollCheck.poll.canvas.toBuffer(), `Poll.png`)).setColor("#F24646")] }).catch(() => { });
|
||||||
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);
|
return client.polls.delete(message.id);
|
||||||
}
|
} else if (convert === 0 && convert !== 10 || 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 (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;
|
if (pollCheck.users.includes(userId)) return;
|
||||||
|
|
||||||
pollCheck.users.push(userId);
|
pollCheck.users.push(userId);
|
||||||
const user = client.users.get(userId) || await client.users.fetch(userId);
|
const user = (client.users.get(userId)) || await client.users.fetch(userId);
|
||||||
|
// console.log(user.avatar.id ? user.avatar.createFileURL() : 'https://chat.f95.io/api/users/01HATCWS7XZ7KEHW64AV20SMKR/default_avatar')
|
||||||
await pollCheck.poll.addVote(convert, userId, 'https://chat.f95.io/api/users/01HATCWS7XZ7KEHW64AV20SMKR/default_avatar', message.id);
|
await pollCheck.poll.addVote(convert, userId, 'https://chat.f95.io/api/users/01HATCWS7XZ7KEHW64AV20SMKR/default_avatar', message.id);
|
||||||
|
message.edit({ embeds: [new Embed().setDescription(tooMuch.length > 0 ? tooMuch.map(e => e).join("\n") : null).setMedia(await client.Uploader.upload(pollCheck.poll.canvas.toBuffer(), `Poll.png`)).setColor("#A52F05")] }).catch(() => { });
|
||||||
const tooMuch = [];
|
client.reactions.set(userId, Date.now() + 3000)
|
||||||
if (pollCheck.poll.options.description.length > 80) {
|
return setTimeout(() => client.reactions.delete(userId), 3000)
|
||||||
tooMuch.push(`**${client.translate.get(pollCheck.lang, "Events.messageReactionAdd.title")}**: ${pollCheck.poll.options.description}`);
|
} else return;
|
||||||
}
|
} else {
|
||||||
pollCheck.poll.voteOptions.name.filter(e => e).forEach((e, i) => {
|
const db = await Giveaways.findOne({ messageId: message.id });
|
||||||
if (e.length > 70) {
|
if (db) {
|
||||||
tooMuch.push(`**${i + 1}.** ${e}`);
|
if (emojiId === client.config.emojis.confetti && db && !db.ended) {
|
||||||
}
|
if (client.reactions.get(userId)) return;
|
||||||
});
|
if (db.users.find(u => u.userID === userId)) return;
|
||||||
|
|
||||||
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<void>}
|
|
||||||
*/
|
|
||||||
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.users.push({ userID: userId });
|
||||||
db.picking.push({ userID: userId });
|
db.picking.push({ userID: userId });
|
||||||
await db.save();
|
db.save();
|
||||||
|
|
||||||
client.reactions.set(userId, Date.now() + 3000);
|
client.reactions.set(userId, Date.now() + 3000)
|
||||||
setTimeout(() => client.reactions.delete(userId), 3000);
|
setTimeout(() => client.reactions.delete(userId), 3000)
|
||||||
|
|
||||||
await client.users.get(userId)?.openDM()
|
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(() => { });
|
||||||
.then(dm => dm.sendMessage(
|
} else if (emojiId === client.config.emojis.stop && db && db.owner === userId && !db.ended) {
|
||||||
`${client.translate.get(db.lang, "Events.messageReactionAdd.joined")} [${db.prize}](https://chat.f95.io/server/${db.serverId}/channel/${db.channelId}/${db.messageId})!\n` +
|
let endDate = Date.now();
|
||||||
`${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) {
|
if (db.users.length === 0) {
|
||||||
const noUsers = new Embed()
|
const noUsers = new Embed()
|
||||||
.setColor("#A52F05")
|
.setColor("#A52F05")
|
||||||
.setTitle(client.translate.get(db.lang, "Events.messageReactionAdd.giveaway"))
|
.setTitle(client.translate.get(db.lang, "Events.messageReactionAdd.giveaway"))
|
||||||
.setDescription(
|
.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")}: <t:${Math.floor((endDate) / 1000)}:R>\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}` : ``}`)
|
||||||
`${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")}: <t:${Math.floor(endDate / 1000)}:R>\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.updateOne({ ended: true, endDate: endDate })
|
||||||
await db.save();
|
await db.save();
|
||||||
return await client.api.patch(`/channels/${db.channelId}/messages/${db.messageId}`, { embeds: [noUsers] });
|
return await client.api.patch(`/channels/${db.channelId}/messages/${db.messageId}`, { "embeds": [noUsers] });
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < db.winners; i++) {
|
for (let i = 0; i < db.winners; i++) {
|
||||||
const winner = db.picking[Math.floor(Math.random() * db.picking.length)];
|
let winner = db.picking[Math.floor(Math.random() * db.picking.length)];
|
||||||
if (winner) {
|
if (winner) {
|
||||||
db.picking = db.picking.filter(object => object.userID !== winner.userID);
|
const filtered = db.picking.filter(object => object.userID != winner.userID)
|
||||||
db.pickedWinners.push({ id: winner.userID });
|
db.picking = filtered;
|
||||||
|
db.pickedWinners.push({ id: winner.userID })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.updateOne({ ended: true, endDate });
|
await db.updateOne({ ended: true, endDate: endDate })
|
||||||
await db.save();
|
await db.save();
|
||||||
|
|
||||||
const noUsers = new Embed()
|
const noUsers = new Embed()
|
||||||
.setColor("#A52F05")
|
.setColor("#A52F05")
|
||||||
.setTitle(client.translate.get(db.lang, "Events.messageReactionAdd.giveaway"))
|
.setTitle(client.translate.get(db.lang, "Events.messageReactionAdd.giveaway"))
|
||||||
.setDescription(
|
.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")}: <t:${Math.floor((endDate) / 1000)}:R>\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}` : ``}`)
|
||||||
`${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")}: <t:${Math.floor(endDate / 1000)}:R>\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(() => {});
|
message.edit({ embeds: [noUsers] }).catch(() => { });
|
||||||
await client.api.post(`/channels/${db.channelId}/messages`, {
|
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(() => { });
|
||||||
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})**!`
|
client.reactions.set(userId, Date.now() + 3000)
|
||||||
}).catch(() => {});
|
setTimeout(() => client.reactions.delete(userId), 3000)
|
||||||
|
|
||||||
client.reactions.set(userId, Date.now() + 3000);
|
|
||||||
setTimeout(() => client.reactions.delete(userId), 3000);
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
const db2 = await client.database.getGuild(message.server.id, true)
|
||||||
/**
|
if (db2 && db2.roles.find(e => e.msgId === message.id) && db2.roles.find(e => e.roles.find(e => e.emoji === emojiId))) {
|
||||||
* 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<void>}
|
|
||||||
*/
|
|
||||||
async function handleRoleReaction(client, message, db, userId, emojiId) {
|
|
||||||
if (client.reactions.get(userId)) return;
|
if (client.reactions.get(userId)) return;
|
||||||
|
|
||||||
const roles = [];
|
const roles = [];
|
||||||
db.roles.find(e => e.msgId === message.id).roles.map(e => roles.push(e));
|
db2.roles.find(e => e.msgId === message.id).roles.map(e => roles.push(e));
|
||||||
const role = roles.find(e => e.emoji === emojiId);
|
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);
|
const member = await (client.servers.get(message.server.id) || await client.servers.fetch(message.server.id))?.fetchMember(userId);
|
||||||
if (!member) return;
|
if (!member) return;
|
||||||
|
|
||||||
@ -297,66 +207,14 @@ async function handleRoleReaction(client, message, db, userId, emojiId) {
|
|||||||
setTimeout(() => client.reactions.delete(userId), 3000);
|
setTimeout(() => client.reactions.delete(userId), 3000);
|
||||||
|
|
||||||
dataRoles.push(role.role);
|
dataRoles.push(role.role);
|
||||||
await member.edit({ roles: dataRoles }).catch(() => { error = true });
|
await member.edit({ roles: dataRoles }).catch(() => { error = true })
|
||||||
|
|
||||||
if (db.dm) {
|
if (error && db2.dm) {
|
||||||
const dmMessage = error
|
member?.user?.openDM().then((dm) => { dm.sendMessage(`${client.translate.get(db2.language, "Events.messageReactionAdd.noPerms").replace("{role}", `**${role.name}**`)}!`) }).catch(() => { });
|
||||||
? client.translate.get(db.language, "Events.messageReactionAdd.noPerms").replace("{role}", `**${role.name}**`)
|
} else if (db2.dm) {
|
||||||
: client.translate.get(db.language, "Events.messageReactionAdd.success").replace("{role}", `**${role.name}**`);
|
member?.user?.openDM().then((dm) => { dm.sendMessage(`${client.translate.get(db2.language, "Events.messageReactionAdd.success").replace("{role}", `**${role.name}**`)}!`) }).catch(() => { });
|
||||||
|
}
|
||||||
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<void>}
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,133 +1,80 @@
|
|||||||
const path = require("path");
|
const Embed = require("../functions/embed");
|
||||||
const Embed = require(path.join(__dirname, "../functions/embed"));
|
const Giveaways = require("../models/giveaways");
|
||||||
const Giveaways = require(path.join(__dirname, "../models/giveaways"));
|
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 = /^([A-Z0-9]+)/;
|
||||||
|
|
||||||
// Constants
|
module.exports = async (client, message, userId, emojiId) => {
|
||||||
const EMOJIS = [
|
const pollCheck = client.polls.get(message.id);
|
||||||
{ name: "1️⃣", id: 0 }, { name: "2️⃣", id: 1 }, { name: "3️⃣", id: 2 },
|
const collector = client.messageCollector.get(userId);
|
||||||
{ name: "4️⃣", id: 3 }, { name: "5️⃣", id: 4 }, { name: "6️⃣", id: 5 },
|
const editCollector = client.messageEdit.get(userId);
|
||||||
{ name: "7️⃣", id: 6 }, { name: "8️⃣", id: 7 }, { name: "9️⃣", id: 8 },
|
|
||||||
{ name: "🔟", id: 9 }, { name: "🛑", id: "stop" }
|
|
||||||
];
|
|
||||||
const COLORS_REGEX = /^([A-Z0-9]+)/;
|
|
||||||
|
|
||||||
/**
|
if (collector && collector.messageId === message.id && collector.channelId === message.channelId) {
|
||||||
* Handles message collector reaction removal
|
|
||||||
* @param {Object} client - The client instance
|
|
||||||
* @param {Object} message - The message object
|
|
||||||
* @param {string} emojiId - The emoji ID
|
|
||||||
* @param {Object} collector - The message collector
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function handleMessageCollector(client, message, emojiId, collector) {
|
|
||||||
const emoji = collector.rolesDone.find(e => e.emoji === emojiId);
|
const emoji = collector.rolesDone.find(e => e.emoji === emojiId);
|
||||||
if (!emoji) return;
|
if (emoji) {
|
||||||
|
collector.rolesDone = collector.rolesDone.filter(object => object.emoji != emojiId);
|
||||||
collector.rolesDone = collector.rolesDone.filter(object => object.emoji !== emojiId);
|
|
||||||
collector.roles.push([emoji.role, { name: emoji.name, colour: emoji.color }]);
|
collector.roles.push([emoji.role, { name: emoji.name, colour: emoji.color }]);
|
||||||
collector.regex.push(emoji.name);
|
collector.regex.push(emoji.name);
|
||||||
|
|
||||||
const emote = COLORS_REGEX.test(emojiId) ? `:${emojiId}:` : emojiId;
|
if (colors.test(emojiId)) emote = `:${emojiId}:`;
|
||||||
const content = collector.type === "content"
|
else if (!colors.test(emojiId)) emote = emojiId
|
||||||
? { content: message.content.replace(`${emote} $\\text{\\textcolor{${emoji.color}}{${emoji.name}}}$`, `{role:${emoji.name}}`) }
|
return message.edit(collector.type === "content" ? { content: message.content.replace(`${emote} $\\text{\\textcolor{${emoji.color}}{${emoji.name}}}$`, `{role:${emoji.name}}`) } : { embeds: [new Embed().setColor("#A52F05").setDescription(client.messages.get(message.id).embeds[0].description.replace(`{role:${editCollector.regex[0]}}`, `:${emojiId}: $\\text{\\textcolor{${editCollector.roles[0][1].colour?.includes("linear-gradient") ? '#000000' : editCollector.roles[0][1].colour}}{${editCollector.roles[0][1].name}}}$`))] }).catch(() => { });
|
||||||
: { embeds: [new Embed().setColor("#A52F05").setDescription(client.messages.get(message.id).embeds[0].description.replace(`{role:${collector.regex[0]}}`, `:${emojiId}: $\\text{\\textcolor{${collector.roles[0][1].colour?.includes("linear-gradient") ? '#000000' : collector.roles[0][1].colour}}{${collector.roles[0][1].name}}}$`))] };
|
|
||||||
|
|
||||||
return message.edit(content).catch(() => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles poll reaction removal
|
|
||||||
* @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<void>}
|
|
||||||
*/
|
|
||||||
async function handlePoll(client, message, pollCheck, userId, emojiId) {
|
|
||||||
if (client.reactions.get(userId)) {
|
|
||||||
return client.users.get(userId)?.openDM()
|
|
||||||
.then(dm => dm.sendMessage(client.translate.get(pollCheck.language, "Events.messageReactionRemove.tooFast")))
|
|
||||||
.catch(() => {});
|
|
||||||
}
|
}
|
||||||
|
} else if (editCollector && editCollector.messageId === message.id && editCollector.channelId === message.channelId) {
|
||||||
|
const emoji = editCollector.rolesDone.find(e => e.emoji === emojiId);
|
||||||
|
if (emoji) {
|
||||||
|
editCollector.rolesDone = editCollector.rolesDone.filter(object => object.emoji != emojiId);
|
||||||
|
editCollector.roles.push([emoji.role, { name: emoji.name, colour: emoji.color }]);
|
||||||
|
editCollector.regex.push(emoji.name);
|
||||||
|
|
||||||
const convert = EMOJIS.findIndex(e => e.name === emojiId);
|
if (colors.test(emojiId)) emote = `:${emojiId}:`;
|
||||||
if (convert !== 0 && convert === 10 || convert === -1) return;
|
else if (!colors.test(emojiId)) emote = emojiId
|
||||||
|
return message.edit(editCollector.type === "content" ? { content: message.content.replace(`${emote} $\\text{\\textcolor{${emoji.color}}{${emoji.name}}}$`, `{role:${emoji.name}}`) } : { embeds: [new Embed().setColor("#A52F05").setDescription(client.messages.get(message.id).embeds[0].description.replace(`{role:${editCollector.regex[0]}}`, `:${emojiId}: $\\text{\\textcolor{${editCollector.roles[0][1].colour?.includes("linear-gradient") ? '#000000' : editCollector.roles[0][1].colour}}{${editCollector.roles[0][1].name}}}$`))] }).catch(() => { });
|
||||||
|
}
|
||||||
|
} else if (pollCheck) {
|
||||||
|
if (client.reactions.get(userId)) return client.users.get(userId)?.openDM().then(dm => dm.sendMessage(client.translate.get(pollCheck.language, "Events.messageReactionRemove.tooFast"))).catch(() => { });
|
||||||
|
let convert = emojis.findIndex(e => e.name === emojiId);
|
||||||
|
if (convert === 0 && convert !== 10 || convert !== -1 && convert !== 10) {
|
||||||
if (!pollCheck.users.includes(userId)) return;
|
if (!pollCheck.users.includes(userId)) return;
|
||||||
|
|
||||||
const tooMuch = [];
|
let tooMuch = [];
|
||||||
if (pollCheck.poll.options.description.length > 80) {
|
if (pollCheck.poll.options.description.length > 80) tooMuch.push(`**${client.translate.get(pollCheck.language, "Events.messageReactionRemove.title")}**: ${pollCheck.poll.options.description}`)
|
||||||
tooMuch.push(`**${client.translate.get(pollCheck.language, "Events.messageReactionRemove.title")}**: ${pollCheck.poll.options.description}`);
|
|
||||||
}
|
|
||||||
pollCheck.poll.voteOptions.name.filter(e => e).forEach((e, i) => {
|
pollCheck.poll.voteOptions.name.filter(e => e).forEach((e, i) => {
|
||||||
|
i++
|
||||||
if (e.length > 70) {
|
if (e.length > 70) {
|
||||||
tooMuch.push(`**${i + 1}.** ${e}`);
|
tooMuch.push(`**${i}.** ${e}`)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pollCheck.users = pollCheck.users.filter(object => object !== userId);
|
pollCheck.users = pollCheck.users.filter(object => object != userId);
|
||||||
const user = client.users.get(userId) || await client.users.fetch(userId);
|
const user = (client.users.get(userId)) || await client.users.fetch(userId);
|
||||||
await pollCheck.poll.removeVote(convert, userId, 'https://chat.f95.io/api/users/01HATCWS7XZ7KEHW64AV20SMKR/default_avatar', message.id);
|
await pollCheck.poll.removeVote(convert, userId, 'https://chat.f95.io/api/users/01HATCWS7XZ7KEHW64AV20SMKR/default_avatar', message.id);
|
||||||
|
message.edit({ embeds: [new Embed().setDescription(tooMuch.length > 0 ? tooMuch.map(e => e).join("\n") : null).setMedia(await client.Uploader.upload(pollCheck.poll.canvas.toBuffer(), `Poll.png`)).setColor("#A52F05")] }).catch(() => { });
|
||||||
await message.edit({
|
client.reactions.set(userId, Date.now() + 3000)
|
||||||
embeds: [new Embed()
|
return setTimeout(() => client.reactions.delete(userId), 3000)
|
||||||
.setDescription(tooMuch.length > 0 ? tooMuch.join("\n") : null)
|
} else return;
|
||||||
.setMedia(await client.Uploader.upload(pollCheck.poll.canvas.toBuffer(), `Poll.png`))
|
} else {
|
||||||
.setColor("#A52F05")]
|
|
||||||
}).catch(() => {});
|
|
||||||
|
|
||||||
client.reactions.set(userId, Date.now() + 3000);
|
|
||||||
setTimeout(() => client.reactions.delete(userId), 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles giveaway reaction removal
|
|
||||||
* @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<void>}
|
|
||||||
*/
|
|
||||||
async function handleGiveaway(client, message, db, userId, emojiId) {
|
|
||||||
if (client.reactions.get(userId)) return;
|
if (client.reactions.get(userId)) return;
|
||||||
|
const db = await Giveaways.findOne({ messageId: message.id });
|
||||||
if (emojiId === client.config.emojis.confetti && !db.ended) {
|
if (db && !db.ended) {
|
||||||
|
if (emojiId === client.config.emojis.confetti) {
|
||||||
if (!db.users.find(u => u.userID === userId)) return;
|
if (!db.users.find(u => u.userID === userId)) return;
|
||||||
|
const filtered = db.users.filter(object => object.userID != userId)
|
||||||
|
db.users = filtered;
|
||||||
|
const filtered2 = db.picking.filter(object => object.userID != userId)
|
||||||
|
db.picking = filtered2;
|
||||||
|
db.save();
|
||||||
|
|
||||||
db.users = db.users.filter(object => object.userID !== userId);
|
client.reactions.set(userId, Date.now() + 3000)
|
||||||
db.picking = db.picking.filter(object => object.userID !== userId);
|
setTimeout(() => client.reactions.delete(userId), 3000)
|
||||||
await db.save();
|
|
||||||
|
|
||||||
client.reactions.set(userId, Date.now() + 3000);
|
client.users.get(userId)?.openDM().then(dm => dm.sendMessage(`${client.translate.get(pollCheck.language, "Events.messageReactionRemove.left")} [${db.prize}](https://chat.f95.io/server/${db.serverId}/channel/${db.channelId}/${db.messageId})!\n${client.translate.get(pollCheck.language, "Events.messageReactionRemove.left2")} **${db.users.length}** ${client.translate.get(pollCheck.language, "Events.messageReactionRemove.left")}!`)).catch(() => { });
|
||||||
setTimeout(() => client.reactions.delete(userId), 3000);
|
|
||||||
|
|
||||||
await client.users.get(userId)?.openDM()
|
|
||||||
.then(dm => dm.sendMessage(
|
|
||||||
`${client.translate.get(db.language, "Events.messageReactionRemove.left")} [${db.prize}](https://chat.f95.io/server/${db.serverId}/channel/${db.channelId}/${db.messageId})!\n` +
|
|
||||||
`${client.translate.get(db.language, "Events.messageReactionRemove.left2")} **${db.users.length}** ${client.translate.get(db.language, "Events.messageReactionRemove.left")}!`
|
|
||||||
))
|
|
||||||
.catch(() => {});
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
const db2 = await client.database.getGuild(message.server.id, true)
|
||||||
/**
|
if (db2 && db2.roles.find(e => e.msgId === message.id) && db2.roles.find(e => e.roles.find(e => e.emoji === emojiId))) {
|
||||||
* Handles role reaction removal
|
|
||||||
* @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<void>}
|
|
||||||
*/
|
|
||||||
async function handleRoleReaction(client, message, db, userId, emojiId) {
|
|
||||||
if (client.reactions.get(userId)) return;
|
|
||||||
|
|
||||||
const roles = [];
|
const roles = [];
|
||||||
db.roles.find(e => e.msgId === message.id).roles.map(e => roles.push(e));
|
db2.roles.find(e => e.msgId === message.id).roles.map(e => roles.push(e));
|
||||||
const role = roles.find(e => e.emoji === emojiId);
|
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);
|
const member = await (client.servers.get(message.server.id) || await client.servers.fetch(message.server.id))?.fetchMember(userId);
|
||||||
if (!member) return;
|
if (!member) return;
|
||||||
|
|
||||||
@ -139,61 +86,15 @@ async function handleRoleReaction(client, message, db, userId, emojiId) {
|
|||||||
client.reactions.set(userId, Date.now() + 3000);
|
client.reactions.set(userId, Date.now() + 3000);
|
||||||
setTimeout(() => client.reactions.delete(userId), 3000);
|
setTimeout(() => client.reactions.delete(userId), 3000);
|
||||||
|
|
||||||
dataRoles = dataRoles.filter(object => object !== role.role);
|
dataRoles = dataRoles.filter(object => object != role.role);
|
||||||
await member.edit({ roles: dataRoles }).catch(() => { error = true });
|
await member.edit({ roles: dataRoles }).catch(() => { error = true })
|
||||||
|
|
||||||
if (db.dm) {
|
if (error) {
|
||||||
const dmMessage = error
|
if (db2.dm) member?.user?.openDM().then((dm) => { dm.sendMessage(`${client.translate.get(db2.language, "Events.messageReactionRemove.noPerms").replace("{role}", `**${role.name}**`)}!`) }).catch(() => { });
|
||||||
? client.translate.get(db.language, "Events.messageReactionRemove.noPerms").replace("{role}", `**${role.name}**`)
|
} else {
|
||||||
: client.translate.get(db.language, "Events.messageReactionRemove.success").replace("{role}", `**${role.name}**`);
|
if (db2.dm) member?.user?.openDM().then((dm) => { dm.sendMessage(`${client.translate.get(db2.language, "Events.messageReactionRemove.success").replace("{role}", `**${role.name}**`)}!`) }).catch(() => { });
|
||||||
|
}
|
||||||
await member?.user?.openDM()
|
}
|
||||||
.then(dm => dm.sendMessage(dmMessage))
|
}
|
||||||
.catch(() => {});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Main event handler for message reaction removal
|
|
||||||
* @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<void>}
|
|
||||||
*/
|
|
||||||
module.exports = async (client, message, userId, emojiId) => {
|
|
||||||
try {
|
|
||||||
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.channelId === message.channelId) {
|
|
||||||
return await handleMessageCollector(client, message, emojiId, collector);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle edit collector
|
|
||||||
if (editCollector && editCollector.messageId === message.id && editCollector.channelId === message.channelId) {
|
|
||||||
return await handleMessageCollector(client, message, emojiId, editCollector);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle poll
|
|
||||||
if (pollCheck) {
|
|
||||||
return await handlePoll(client, message, pollCheck, userId, emojiId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle giveaway
|
|
||||||
const giveaway = await Giveaways.findOne({ messageId: message.id });
|
|
||||||
if (giveaway && !giveaway.ended) {
|
|
||||||
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 messageReactionRemove:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
const path = require("path");
|
const Embed = require("../functions/embed")
|
||||||
const Embed = require(path.join(__dirname, "../functions/embed"));
|
|
||||||
module.exports = async (client, server) => {
|
module.exports = async (client, server) => {
|
||||||
//console.log("join", server)
|
//console.log("join", server)
|
||||||
// await client.database.getGuild(server.id, true)
|
// await client.database.getGuild(server.id, true)
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
const path = require("path");
|
const Embed = require("../functions/embed")
|
||||||
const Embed = require(path.join(__dirname, "../functions/embed"));
|
|
||||||
module.exports = async (client, server) => {
|
module.exports = async (client, server) => {
|
||||||
//console.log("delete",server)
|
//console.log("delete",server)
|
||||||
// await client.database.deleteGuild(server.id)
|
// await client.database.deleteGuild(server.id)
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
const path = require("path");
|
|
||||||
let type;
|
let type;
|
||||||
module.exports = async (client, member, memberOld) => {
|
module.exports = async (client, member, memberOld) => {
|
||||||
// Work in progress
|
// Work in progress
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
const path = require("path");
|
const db = require("../models/logging");
|
||||||
const db = require(path.join(__dirname, "../models/logging"));
|
|
||||||
|
|
||||||
async function audit(type, message, cmd) {
|
async function audit(type, message, cmd) {
|
||||||
const audit = new db();
|
const audit = new db();
|
||||||
|
|||||||
@ -1,69 +1,23 @@
|
|||||||
const path = require("path");
|
const db = require("../models/polls");
|
||||||
const db = require(path.join(__dirname, "../models/polls"));
|
const Polls = require("./poll");
|
||||||
const Polls = require(path.join(__dirname, "./poll"));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks and processes all active polls in the database
|
|
||||||
* @param {Object} client - The Discord client instance
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function checkPolls(client) {
|
async function checkPolls(client) {
|
||||||
|
let polls = await db.find();
|
||||||
|
if (!polls || polls.length === 0) return;
|
||||||
|
let i = 0;
|
||||||
|
for (let poll of polls) {
|
||||||
|
i++
|
||||||
|
setTimeout(async () => {
|
||||||
|
const time = poll.now - (Date.now() - poll.time), users = poll.users, avatars = poll.avatars, votes = poll.votes, desc = poll.desc, name = poll.name, names = poll.options, owner = poll.owner, lang = poll.lang;
|
||||||
|
const newPoll = new Polls({ time, client, name: { name: name, description: desc }, options: names, votes: votes, users: users, avatars: avatars, owner: owner, lang: lang })
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const polls = await db.find();
|
await client.channels.get(poll.channelId).fetchMessage(poll.messageId).catch(() => { return });
|
||||||
if (!polls?.length) return;
|
const msg = await client.messages.get(poll.messageId);
|
||||||
|
if (msg) newPoll.start(msg, newPoll);
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
// Process polls concurrently with a small delay between each
|
poll.deleteOne({ messageId: poll.messageId });
|
||||||
await Promise.all(polls.map(async (poll, index) => {
|
}, i * 700);
|
||||||
try {
|
|
||||||
// Add small delay between processing each poll to prevent rate limiting
|
|
||||||
await new Promise(resolve => setTimeout(resolve, index * 700));
|
|
||||||
|
|
||||||
const {
|
|
||||||
now,
|
|
||||||
time,
|
|
||||||
users,
|
|
||||||
avatars,
|
|
||||||
votes,
|
|
||||||
desc,
|
|
||||||
name,
|
|
||||||
options: names,
|
|
||||||
owner,
|
|
||||||
lang,
|
|
||||||
channelId,
|
|
||||||
messageId
|
|
||||||
} = poll;
|
|
||||||
|
|
||||||
const timeRemaining = now - (Date.now() - time);
|
|
||||||
|
|
||||||
const newPoll = new Polls({
|
|
||||||
time: timeRemaining,
|
|
||||||
client,
|
|
||||||
name: { name, description: desc },
|
|
||||||
options: names,
|
|
||||||
votes,
|
|
||||||
users,
|
|
||||||
avatars,
|
|
||||||
owner,
|
|
||||||
lang
|
|
||||||
});
|
|
||||||
|
|
||||||
// Attempt to fetch and process the message
|
|
||||||
const channel = client.channels.get(channelId);
|
|
||||||
if (!channel) return;
|
|
||||||
|
|
||||||
const message = await channel.fetchMessage(messageId).catch(() => null);
|
|
||||||
if (message) {
|
|
||||||
await newPoll.start(message, newPoll);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up the poll from database
|
|
||||||
await poll.deleteOne({ messageId });
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error processing poll ${poll.messageId}:`, error);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in checkPolls:', error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,72 +1,23 @@
|
|||||||
const path = require("path");
|
const db = require("../models/guilds");
|
||||||
const db = require(path.join(__dirname, "../models/guilds"));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks and validates role reaction messages across all guilds
|
|
||||||
* @param {Object} client - Discord client instance
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function checkRoles(client) {
|
async function checkRoles(client) {
|
||||||
try {
|
let rr = await db.find({ $expr: { $gt: [{ $size: "$roles" }, 0] } });
|
||||||
// Find all guilds with role reactions
|
if (!rr || rr.length === 0) return;
|
||||||
const guildsWithRoles = await db.find({
|
let i = 0;
|
||||||
$expr: { $gt: [{ $size: "$roles" }, 0] }
|
let ii = 0;
|
||||||
});
|
for (let r of rr) {
|
||||||
|
i++
|
||||||
if (!guildsWithRoles?.length) return;
|
setTimeout(async () => {
|
||||||
|
r.roles.map((role) => {
|
||||||
// Process each guild sequentially to avoid rate limits
|
ii++
|
||||||
for (const guild of guildsWithRoles) {
|
setTimeout(async () => {
|
||||||
try {
|
if (!client.channels.get(role.chanId) && role.roles.length === 0) {
|
||||||
await processGuildRoles(client, guild);
|
return await client.database.updateGuild(r.id, { roles: r.roles.filter(e => e.msgId !== role.msgId) });
|
||||||
} catch (error) {
|
}
|
||||||
console.error(`Error processing guild ${guild.id}:`, error);
|
|
||||||
}
|
await client.channels.get(role.chanId)?.fetchMessage(role.msgId).catch(() => { });
|
||||||
}
|
}, ii * 700);
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in checkRoles:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process role reactions for a single guild
|
|
||||||
* @param {Object} client - Discord client instance
|
|
||||||
* @param {Object} guild - Guild data from database
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function processGuildRoles(client, guild) {
|
|
||||||
const validRoles = [];
|
|
||||||
const invalidRoles = [];
|
|
||||||
|
|
||||||
// Process each role reaction message
|
|
||||||
for (const role of guild.roles) {
|
|
||||||
try {
|
|
||||||
const channel = client.channels.get(role.chanId);
|
|
||||||
|
|
||||||
// Skip if channel doesn't exist or role array is empty
|
|
||||||
if (!channel || !role.roles?.length) {
|
|
||||||
invalidRoles.push(role);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify message exists
|
|
||||||
const message = await channel.fetchMessage(role.msgId).catch(() => null);
|
|
||||||
if (message) {
|
|
||||||
validRoles.push(role);
|
|
||||||
} else {
|
|
||||||
invalidRoles.push(role);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error processing role ${role.msgId} in guild ${guild.id}:`, error);
|
|
||||||
invalidRoles.push(role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update guild with only valid roles if there were any invalid ones
|
|
||||||
if (invalidRoles.length > 0) {
|
|
||||||
await client.database.updateGuild(guild.id, {
|
|
||||||
roles: validRoles
|
|
||||||
});
|
});
|
||||||
|
}, i * 600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,45 +1,26 @@
|
|||||||
/**
|
|
||||||
* ANSI color codes mapping for terminal text coloring
|
|
||||||
* @type {Object<string, string>}
|
|
||||||
*/
|
|
||||||
const ANSI_COLORS = {
|
|
||||||
'0': '\x1b[30m', // Black
|
|
||||||
'1': '\x1b[34m', // Dark Blue
|
|
||||||
'2': '\x1b[32m', // Dark Green
|
|
||||||
'3': '\x1b[36m', // Dark Aqua
|
|
||||||
'4': '\x1b[31m', // Dark Red
|
|
||||||
'5': '\x1b[35m', // Dark Purple
|
|
||||||
'6': '\x1b[33m', // Gold
|
|
||||||
'7': '\x1b[37m', // Gray
|
|
||||||
'8': '\x1b[90m', // Dark Gray
|
|
||||||
'9': '\x1b[94m', // Blue
|
|
||||||
'a': '\x1b[92m', // Green
|
|
||||||
'b': '\x1b[96m', // Aqua
|
|
||||||
'c': '\x1b[91m', // Red
|
|
||||||
'd': '\x1b[95m', // Light Purple
|
|
||||||
'e': '\x1b[93m', // Yellow
|
|
||||||
'f': '\x1b[97m', // White
|
|
||||||
'r': '\x1b[0m', // Reset
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates color codes in text to ANSI color sequences
|
|
||||||
* @param {string} altColorChar - The character used to prefix color codes (e.g., '&' or '§')
|
|
||||||
* @param {string} textToTranslate - The text containing color codes to translate
|
|
||||||
* @returns {string} The text with color codes replaced by ANSI sequences
|
|
||||||
* @throws {Error} If altColorChar is not a single character
|
|
||||||
*/
|
|
||||||
function colors(altColorChar, textToTranslate) {
|
function colors(altColorChar, textToTranslate) {
|
||||||
if (typeof altColorChar !== 'string' || altColorChar.length !== 1) {
|
const colorMap = {
|
||||||
throw new Error('altColorChar must be a single character');
|
[`${altColorChar}0`]: '\x1b[30m', // Black
|
||||||
}
|
[`${altColorChar}1`]: '\x1b[34m', // Dark Blue
|
||||||
|
[`${altColorChar}2`]: '\x1b[32m', // Dark Green
|
||||||
if (typeof textToTranslate !== 'string') {
|
[`${altColorChar}3`]: '\x1b[36m', // Dark Aqua
|
||||||
throw new Error('textToTranslate must be a string');
|
[`${altColorChar}4`]: '\x1b[31m', // Dark Red
|
||||||
}
|
[`${altColorChar}5`]: '\x1b[35m', // Dark Purple
|
||||||
|
[`${altColorChar}6`]: '\x1b[33m', // Gold
|
||||||
|
[`${altColorChar}7`]: '\x1b[37m', // Gray
|
||||||
|
[`${altColorChar}8`]: '\x1b[90m', // Dark Gray
|
||||||
|
[`${altColorChar}9`]: '\x1b[94m', // Blue
|
||||||
|
[`${altColorChar}a`]: '\x1b[92m', // Green
|
||||||
|
[`${altColorChar}b`]: '\x1b[96m', // Aqua
|
||||||
|
[`${altColorChar}c`]: '\x1b[91m', // Red
|
||||||
|
[`${altColorChar}d`]: '\x1b[95m', // Light Purple
|
||||||
|
[`${altColorChar}e`]: '\x1b[93m', // Yellow
|
||||||
|
[`${altColorChar}f`]: '\x1b[97m', // White
|
||||||
|
[`${altColorChar}r`]: '\x1b[0m', // Reset
|
||||||
|
};
|
||||||
|
|
||||||
const regex = new RegExp(`${altColorChar}([0-9a-fr])`, 'g');
|
const regex = new RegExp(`${altColorChar}([0-9a-fr])`, 'g');
|
||||||
return textToTranslate.replace(regex, (_, code) => ANSI_COLORS[code] || '');
|
return textToTranslate.replace(regex, (match, code) => colorMap[`${altColorChar}${code}`] || '');
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = colors;
|
module.exports = colors;
|
||||||
|
|||||||
@ -1,40 +1,11 @@
|
|||||||
/**
|
function dhms(str, sec = false) {
|
||||||
* Converts a time string (e.g., "1d2h3m4s") into milliseconds or seconds
|
const x = sec ? 1 : 1000;
|
||||||
* @param {string} timeStr - The time string to convert (e.g., "1d2h3m4s")
|
if (typeof str !== 'string') return 0;
|
||||||
* @param {boolean} [inSeconds=false] - If true, returns result in seconds instead of milliseconds
|
const fixed = str.replace(/\s/g, '');
|
||||||
* @returns {number} The converted time in milliseconds or seconds
|
const tail = +fixed.match(/-?\d+$/g) || 0;
|
||||||
*/
|
const parts = (fixed.match(/-?\d+[^-0-9]+/g) || [])
|
||||||
function dhms(timeStr, inSeconds = false) {
|
.map(v => +v.replace(/[^-0-9]+/g, '') * ({ s: x, m: 60 * x, h: 3600 * x, d: 86400 * x }[v.replace(/[-0-9]+/g, '')] || 0));
|
||||||
// Return 0 for invalid input
|
return [tail, ...parts].reduce((a, b) => a + b, 0);
|
||||||
if (typeof timeStr !== 'string' || !timeStr.trim()) {
|
};
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define time unit multipliers
|
|
||||||
const multipliers = {
|
|
||||||
s: inSeconds ? 1 : 1000,
|
|
||||||
m: inSeconds ? 60 : 60000,
|
|
||||||
h: inSeconds ? 3600 : 3600000,
|
|
||||||
d: inSeconds ? 86400 : 86400000
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove whitespace and split into parts
|
|
||||||
const cleanStr = timeStr.replace(/\s/g, '');
|
|
||||||
|
|
||||||
// Extract the numeric value at the end (if any)
|
|
||||||
const tailMatch = cleanStr.match(/-?\d+$/);
|
|
||||||
const tailValue = tailMatch ? parseInt(tailMatch[0], 10) : 0;
|
|
||||||
|
|
||||||
// Extract and convert time parts
|
|
||||||
const timeParts = (cleanStr.match(/-?\d+[^-0-9]+/g) || [])
|
|
||||||
.map(part => {
|
|
||||||
const value = parseInt(part.replace(/[^-0-9]+/g, ''), 10);
|
|
||||||
const unit = part.replace(/[-0-9]+/g, '');
|
|
||||||
return value * (multipliers[unit] || 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sum all parts including the tail
|
|
||||||
return [tailValue, ...timeParts].reduce((sum, value) => sum + value, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = dhms;
|
module.exports = dhms;
|
||||||
@ -1,34 +1,16 @@
|
|||||||
/**
|
function fetchTime(ms, client, lang) {
|
||||||
* Converts milliseconds into a human-readable time string with localized units
|
var totalSeconds = (ms / 1000);
|
||||||
* @param {number} milliseconds - The time in milliseconds to convert
|
let years = Math.floor(totalSeconds / 31536000);
|
||||||
* @param {Object} client - The client object containing translation functionality
|
totalSeconds %= 31536000;
|
||||||
* @param {string} lang - The language code for translations
|
let days = Math.floor(totalSeconds / 86400);
|
||||||
* @returns {string} Formatted time string with localized units
|
totalSeconds %= 86400;
|
||||||
*/
|
let hours = Math.floor(totalSeconds / 3600);
|
||||||
function fetchTime(milliseconds, client, lang) {
|
totalSeconds %= 3600;
|
||||||
if (!Number.isFinite(milliseconds) || milliseconds < 0) {
|
let minutes = Math.floor(totalSeconds / 60);
|
||||||
throw new Error('Invalid milliseconds value provided');
|
let seconds = totalSeconds % 60;
|
||||||
}
|
seconds = Math.floor(seconds);
|
||||||
|
|
||||||
const timeUnits = [
|
return `${years ? `${years} ${client.translate.get(lang, "Functions.fetchTime.years")},` : ""} ${days ? `${days} ${client.translate.get(lang, "Functions.fetchTime.days")},` : ""} ${hours ? `${hours} ${client.translate.get(lang, "Functions.fetchTime.hours")},` : ""} ${minutes ? `${minutes} ${client.translate.get(lang, "Functions.fetchTime.minutes")},` : ""} ${seconds} ${client.translate.get(lang, "Functions.fetchTime.seconds")}`;
|
||||||
{ value: 31536000, key: 'years' },
|
|
||||||
{ value: 86400, key: 'days' },
|
|
||||||
{ value: 3600, key: 'hours' },
|
|
||||||
{ value: 60, key: 'minutes' },
|
|
||||||
{ value: 1, key: 'seconds' }
|
|
||||||
];
|
|
||||||
|
|
||||||
let remainingSeconds = Math.floor(milliseconds / 1000);
|
|
||||||
|
|
||||||
return timeUnits
|
|
||||||
.map(({ value, key }) => {
|
|
||||||
const unitValue = Math.floor(remainingSeconds / value);
|
|
||||||
remainingSeconds %= value;
|
|
||||||
return unitValue ? `${unitValue} ${client.translate.get(lang, `Functions.fetchTime.${key}`)},` : '';
|
|
||||||
})
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' ')
|
|
||||||
.trim();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = fetchTime;
|
module.exports = fetchTime;
|
||||||
@ -1,75 +1,68 @@
|
|||||||
/**
|
/**
|
||||||
* Enhanced logger utility with date-fns for date formatting
|
* base code taken from https://github.com/Mirasaki/logger
|
||||||
* Original code inspired by https://github.com/Mirasaki/logger
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk'),
|
||||||
const { format, formatInTimeZone } = require('date-fns-tz');
|
moment = require('moment');
|
||||||
|
|
||||||
// Define log levels and their corresponding styles
|
const tagList = {
|
||||||
const LOG_LEVELS = {
|
SYSLOG: chalk.greenBright('[SYSLOG]'),
|
||||||
SYSLOG: { color: 'greenBright', prefix: '[SYSLOG]' },
|
SYSERR: chalk.redBright('[SYSERR]'),
|
||||||
SYSERR: { color: 'redBright', prefix: '[SYSERR]' },
|
SUCCESS: chalk.greenBright('[SUCCESS]'),
|
||||||
SUCCESS: { color: 'greenBright', prefix: '[SUCCESS]' },
|
INFO: chalk.blueBright('[INFO]'),
|
||||||
INFO: { color: 'blueBright', prefix: '[INFO]' },
|
DEBUG: chalk.magentaBright('[DEBUG]'),
|
||||||
DEBUG: { color: 'magentaBright', prefix: '[DEBUG]' },
|
DATA: chalk.yellowBright('[DATA]'),
|
||||||
DATA: { color: 'yellowBright', prefix: '[DATA]' },
|
COMMAND: chalk.whiteBright('[CMD]'),
|
||||||
COMMAND: { color: 'whiteBright', prefix: '[CMD]' },
|
EVENT: chalk.cyanBright('[EVENT]'),
|
||||||
EVENT: { color: 'cyanBright', prefix: '[EVENT]' },
|
ERROR: chalk.redBright('[EVENT]'),
|
||||||
ERROR: { color: 'redBright', prefix: '[ERROR]' },
|
WARN: chalk.yellowBright('[WARN]')
|
||||||
WARN: { color: 'yellowBright', prefix: '[WARN]' }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create tag list with chalk styling
|
|
||||||
const tagList = Object.entries(LOG_LEVELS).reduce((acc, [key, { color, prefix }]) => ({
|
|
||||||
...acc,
|
|
||||||
[key]: chalk[color](prefix)
|
|
||||||
}), {});
|
|
||||||
|
|
||||||
// Calculate longest tag length for alignment
|
|
||||||
const longestTagLength = Math.max(...Object.values(tagList).map(t => t.length));
|
const longestTagLength = Math.max(...Object.values(tagList).map(t => t.length));
|
||||||
|
const getTag = (tag) => `${tagList[tag]}${''.repeat(longestTagLength - tagList[tag].length)}`;
|
||||||
|
const timestamp = () => `${chalk.whiteBright.bold(`[${moment.utc().format('YYYY-MM-DD HH:mm:ss')}]`)}`;
|
||||||
|
|
||||||
/**
|
module.exports = {
|
||||||
* Get formatted tag with proper spacing
|
syslog: (type, str) => console.info(`${timestamp()} ${type ? `${getTag('SYSLOG')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('SYSLOG')}:`} ${str}`),
|
||||||
* @param {string} tag - The log level tag
|
syserr: (type, str) => console.error(`${timestamp()} ${type ? `${getTag('SYSERR')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('SYSERR')} :`} ${str}`),
|
||||||
* @returns {string} Formatted tag with spacing
|
success: (type, str) => console.log(`${timestamp()} ${type ? `${getTag('SUCCESS')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('SUCCESS')}:`} ${str}`),
|
||||||
*/
|
info: (type, str) => console.info(`${timestamp()} ${type ? `${getTag('INFO')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('INFO')}:`} ${str}`),
|
||||||
const getTag = (tag) => `${tagList[tag]}${' '.repeat(longestTagLength - tagList[tag].length)}`;
|
debug: (type, str) => console.log(`${timestamp()} ${type ? `${getTag('DEBUG')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('DEBUG')}:`} ${str}`),
|
||||||
|
data: (type, str) => console.log(`${timestamp()} ${type ? `${getTag('DATA')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('DATA')}:`} ${str}`),
|
||||||
|
command: (type, str) => console.log(`${timestamp()} ${type ? `${getTag('COMMAND')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('COMMAND')}:`} ${str}`),
|
||||||
|
event: (type, str) => console.log(`${timestamp()} ${type ? `${getTag('EVENT')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('EVENT')}:`} ${str}`),
|
||||||
|
error: (type, str) => console.log(`${timestamp()} ${type ? `${getTag('ERROR')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('ERROR')}:`} ${str}`),
|
||||||
|
warn: (type, str) => console.log(`${timestamp()} ${type ? `${getTag('WARN')} ${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : `${getTag('WARN')}:`} ${str}`),
|
||||||
|
|
||||||
/**
|
startLog: (identifier) => console.log(`${timestamp()} ${getTag('DEBUG')} ${chalk.greenBright('[START]')} ${identifier}`),
|
||||||
* Get formatted timestamp
|
endLog: (identifier) => console.log(`${timestamp()} ${getTag('DEBUG')} ${chalk.redBright('[ END ]')} ${identifier}`),
|
||||||
* @returns {string} Formatted timestamp with styling
|
|
||||||
*/
|
|
||||||
const timestamp = () => {
|
|
||||||
const now = new Date();
|
|
||||||
const formattedDate = formatInTimeZone(now, 'UTC', 'yyyy-MM-dd HH:mm:ss');
|
|
||||||
return chalk.whiteBright.bold(`[${formattedDate}]`);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
timestamp,
|
||||||
* Create a log message with proper formatting
|
getExecutionTime: (hrtime) => {
|
||||||
* @param {string} level - Log level
|
const timeSinceHrMs = (
|
||||||
* @param {string} type - Optional type identifier
|
process.hrtime(hrtime)[0] * 1000
|
||||||
* @param {string} message - Log message
|
+ hrtime[1] / 1000000
|
||||||
* @returns {string} Formatted log message
|
).toFixed(2);
|
||||||
*/
|
return `${chalk.yellowBright(
|
||||||
const createLogMessage = (level, type, message) => {
|
(timeSinceHrMs / 1000).toFixed(2))
|
||||||
const typeTag = type ? `${chalk.whiteBright.bgBlue.bold(`[${type}]`)}:` : ':';
|
} seconds (${chalk.yellowBright(timeSinceHrMs)} ms)`;
|
||||||
return `${timestamp()} ${getTag(level)} ${typeTag} ${message}`;
|
},
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
printErr: (err) => {
|
||||||
* Format error stack trace with proper styling
|
if (!(err instanceof Error)) {
|
||||||
* @param {Error} err - Error object
|
console.error(err)
|
||||||
* @returns {string} Formatted error stack trace
|
return;
|
||||||
*/
|
}
|
||||||
const formatErrorStack = (err) => {
|
|
||||||
if (!err.stack) return chalk.red(err);
|
|
||||||
|
|
||||||
return err.stack
|
console.error(
|
||||||
|
!err.stack
|
||||||
|
? chalk.red(err)
|
||||||
|
: err.stack
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.map((msg, index) => {
|
.map((msg, index) => {
|
||||||
if (index === 0) return chalk.red(msg);
|
if (index === 0) {
|
||||||
|
return chalk.red(msg);
|
||||||
|
}
|
||||||
|
|
||||||
const isFailedFunctionCall = index === 1;
|
const isFailedFunctionCall = index === 1;
|
||||||
const traceStartIndex = msg.indexOf('(');
|
const traceStartIndex = msg.indexOf('(');
|
||||||
@ -86,38 +79,7 @@ const formatErrorStack = (err) => {
|
|||||||
: `${chalk.greenBright(functionCall)} ${chalk.grey(trace)}`
|
: `${chalk.greenBright(functionCall)} ${chalk.grey(trace)}`
|
||||||
}`;
|
}`;
|
||||||
})
|
})
|
||||||
.join('\n');
|
.join('\n')
|
||||||
};
|
)
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
syslog: (type, str) => console.info(createLogMessage('SYSLOG', type, str)),
|
|
||||||
syserr: (type, str) => console.error(createLogMessage('SYSERR', type, str)),
|
|
||||||
success: (type, str) => console.log(createLogMessage('SUCCESS', type, str)),
|
|
||||||
info: (type, str) => console.info(createLogMessage('INFO', type, str)),
|
|
||||||
debug: (type, str) => console.log(createLogMessage('DEBUG', type, str)),
|
|
||||||
data: (type, str) => console.log(createLogMessage('DATA', type, str)),
|
|
||||||
command: (type, str) => console.log(createLogMessage('COMMAND', type, str)),
|
|
||||||
event: (type, str) => console.log(createLogMessage('EVENT', type, str)),
|
|
||||||
error: (type, str) => console.log(createLogMessage('ERROR', type, str)),
|
|
||||||
warn: (type, str) => console.log(createLogMessage('WARN', type, str)),
|
|
||||||
|
|
||||||
startLog: (identifier) => console.log(`${timestamp()} ${getTag('DEBUG')} ${chalk.greenBright('[START]')} ${identifier}`),
|
|
||||||
endLog: (identifier) => console.log(`${timestamp()} ${getTag('DEBUG')} ${chalk.redBright('[ END ]')} ${identifier}`),
|
|
||||||
|
|
||||||
timestamp,
|
|
||||||
getExecutionTime: (hrtime) => {
|
|
||||||
const timeSinceHrMs = (
|
|
||||||
process.hrtime(hrtime)[0] * 1000 +
|
|
||||||
hrtime[1] / 1000000
|
|
||||||
).toFixed(2);
|
|
||||||
return `${chalk.yellowBright((timeSinceHrMs / 1000).toFixed(2))} seconds (${chalk.yellowBright(timeSinceHrMs)} ms)`;
|
|
||||||
},
|
|
||||||
|
|
||||||
printErr: (err) => {
|
|
||||||
if (!(err instanceof Error)) {
|
|
||||||
console.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.error(formatErrorStack(err));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1,129 +1,72 @@
|
|||||||
const path = require("path");
|
const Embed = require("../functions/embed");
|
||||||
const Embed = require(path.join(__dirname, "../functions/embed"));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates and processes role assignments from a message
|
|
||||||
* @param {Object} client - The client instance
|
|
||||||
* @param {Object} message - The message object
|
|
||||||
* @param {Object} db - Database instance
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function Collector(client, message, db) {
|
async function Collector(client, message, db) {
|
||||||
const ROLE_REGEX = /{role:(.*?)}/g;
|
const regex = /{role:(.*?)}/;
|
||||||
const MAX_ROLES = 20;
|
const regexAll = /{role:(.*?)}/g;
|
||||||
|
|
||||||
// Get collector for the message author
|
|
||||||
const collector = client.messageCollector.get(message.authorId);
|
const collector = client.messageCollector.get(message.authorId);
|
||||||
|
if (!message.content.match(regexAll) || message.content.match(regexAll)?.length === 0) {
|
||||||
// Validate message contains role tags
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(`${client.translate.get(db.language, "Events.messageCreate.noRoles")}: \`{role:Red}\``)] }, false).catch(() => { return });
|
||||||
const roleMatches = message.content.match(ROLE_REGEX);
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
if (!roleMatches?.length) {
|
|
||||||
await sendErrorResponse(message, client, db, "Events.messageCreate.noRoles", `\`{role:Red}\``);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract role names from message
|
const roles = message.content.match(regexAll).map((r) => r?.match(regex)[1]);
|
||||||
const roleNames = roleMatches.map(match => match.match(/{role:(.*?)}/)[1]);
|
if (roles.length > 20) {
|
||||||
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(client.translate.get(db.language, "Events.messageCreate.maxRoles"))] }, false).catch(() => { return });
|
||||||
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
|
}
|
||||||
|
collector.regex = roles
|
||||||
|
const roleIds = []
|
||||||
|
let newRoles = roles.map((r) => {
|
||||||
|
return [...message.server.roles].map((r) => r).find((role) => r.toLowerCase() === role[1]?.name?.toLowerCase());
|
||||||
|
})
|
||||||
|
newRoles.map((r) => roleIds.push(r));
|
||||||
|
|
||||||
// Check role count limit
|
if (roleIds.map((r) => !r).includes(true)) {
|
||||||
if (roleNames.length > MAX_ROLES) {
|
let unknown = [];
|
||||||
await sendErrorResponse(message, client, db, "Events.messageCreate.maxRoles");
|
roleIds.map((r, i) => {
|
||||||
return;
|
i++
|
||||||
|
if (!r) {
|
||||||
|
unknown.push(roles[i - 1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(`${client.translate.get(db.language, "Events.messageCreate.unknown")}\n${unknown.map(e => `\`{role:${e}}\``).join(", ")}`)] }, false).catch(() => { return });
|
||||||
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
}
|
}
|
||||||
|
|
||||||
collector.regex = roleNames;
|
let duplicate = [];
|
||||||
|
roleIds.map((r, i) => {
|
||||||
|
i++
|
||||||
|
if (roleIds.filter(e => e[0] === r[0]).length > 1) duplicate.push(roleIds[i - 1]);
|
||||||
|
});
|
||||||
|
|
||||||
// Find matching server roles
|
if (duplicate.length > 0) {
|
||||||
const serverRoles = [...message.server.roles].map(([id, role]) => ({ id, role }));
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(`${client.translate.get(db.language, "Events.messageCreate.duplicate")}\n${duplicate.map(e => `\`{role:${e[1].name}}\``)}`)] }, false).catch(() => { return });
|
||||||
const matchedRoles = roleNames.map(name =>
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
serverRoles.find(({ role }) => role.name.toLowerCase() === name.toLowerCase())
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check for unknown roles
|
|
||||||
const unknownRoles = roleNames.filter((name, index) => !matchedRoles[index]);
|
|
||||||
if (unknownRoles.length > 0) {
|
|
||||||
await sendErrorResponse(
|
|
||||||
message,
|
|
||||||
client,
|
|
||||||
db,
|
|
||||||
"Events.messageCreate.unknown",
|
|
||||||
unknownRoles.map(role => `\`{role:${role}}\``).join(", ")
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate roles
|
let positions = [];
|
||||||
const roleIds = matchedRoles.map(({ id }) => id);
|
const botRole = message.channel.server.member.orderedRoles.reverse()[0]
|
||||||
const duplicates = roleIds.filter((id, index) => roleIds.indexOf(id) !== index);
|
|
||||||
if (duplicates.length > 0) {
|
|
||||||
const duplicateRoles = duplicates.map(id =>
|
|
||||||
matchedRoles.find(({ id: roleId }) => roleId === id).role.name
|
|
||||||
);
|
|
||||||
await sendErrorResponse(
|
|
||||||
message,
|
|
||||||
client,
|
|
||||||
db,
|
|
||||||
"Events.messageCreate.duplicate",
|
|
||||||
duplicateRoles.map(name => `\`{role:${name}}\``).join(", ")
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check bot role permissions
|
|
||||||
const botRole = message.channel.server.member.orderedRoles.reverse()[0];
|
|
||||||
if (!botRole) {
|
if (!botRole) {
|
||||||
await sendErrorResponse(message, client, db, "Events.messageCreate.noBotRole");
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(client.translate.get(db.language, "Events.messageCreate.noBotRole"))] }, false).catch(() => { return });
|
||||||
return;
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check role positions
|
roleIds.map((r, i) => {
|
||||||
const invalidPositions = matchedRoles.filter(({ role }) => role.rank <= botRole.rank);
|
i++
|
||||||
if (invalidPositions.length > 0) {
|
if (r[1].rank <= botRole.rank) positions.push(roleIds[i - 1])
|
||||||
await sendErrorResponse(
|
});
|
||||||
message,
|
|
||||||
client,
|
if (positions.length > 0) {
|
||||||
db,
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(`${client.translate.get(db.language, "Events.messageCreate.positions")}\n${positions.map(e => `\`{role:${e[1].name}}\``)}`)] }, false).catch(() => { return });
|
||||||
"Events.messageCreate.positions",
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
invalidPositions.map(({ role }) => `\`{role:${role.name}}\``).join(", ")
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process valid role assignment
|
message.delete().catch(() => { });
|
||||||
await message.delete().catch(() => {});
|
collector.roles = roleIds;
|
||||||
collector.roles = matchedRoles;
|
|
||||||
|
|
||||||
const react = [client.config.emojis.check];
|
const react = [client.config.emojis.check];
|
||||||
const messageContent = collector.type === "content"
|
return message.channel.sendMessage(collector.type === "content" ? { content: message.content, interactions: [react] } : { embeds: [new Embed().setDescription(message.content).setColor("#A52F05")], interactions: [react] }).then((msg) => {
|
||||||
? { content: message.content, interactions: [react] }
|
collector.messageId = msg.id;
|
||||||
: {
|
});
|
||||||
embeds: [new Embed().setDescription(message.content).setColor("#A52F05")],
|
|
||||||
interactions: [react]
|
|
||||||
};
|
|
||||||
|
|
||||||
const sentMessage = await message.channel.sendMessage(messageContent);
|
|
||||||
collector.messageId = sentMessage.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to send error responses
|
|
||||||
* @param {Object} message - The message object
|
|
||||||
* @param {Object} client - The client instance
|
|
||||||
* @param {Object} db - Database instance
|
|
||||||
* @param {string} translationKey - Translation key for the error message
|
|
||||||
* @param {string} [additionalInfo] - Additional information to append to the error message
|
|
||||||
*/
|
|
||||||
async function sendErrorResponse(message, client, db, translationKey, additionalInfo = "") {
|
|
||||||
const errorMessage = additionalInfo
|
|
||||||
? `${client.translate.get(db.language, translationKey)}\n${additionalInfo}`
|
|
||||||
: client.translate.get(db.language, translationKey);
|
|
||||||
|
|
||||||
await message.reply(
|
|
||||||
{ embeds: [new Embed().setColor("#FF0000").setDescription(errorMessage)] },
|
|
||||||
false
|
|
||||||
).catch(() => {});
|
|
||||||
|
|
||||||
await message.react(client.config.emojis.cross).catch(() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Collector;
|
module.exports = Collector;
|
||||||
@ -1,157 +1,72 @@
|
|||||||
const path = require("path");
|
const Embed = require("../functions/embed");
|
||||||
const Embed = require(path.join(__dirname, "../functions/embed"));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates role mentions in a message
|
|
||||||
* @param {string} content - Message content to validate
|
|
||||||
* @param {string} language - User's language setting
|
|
||||||
* @param {Object} client - Discord client instance
|
|
||||||
* @returns {Object} Validation result with roles and error message if any
|
|
||||||
*/
|
|
||||||
function validateRoleMentions(content, language, client) {
|
|
||||||
const regex = /{role:(.*?)}/g;
|
|
||||||
const matches = content.match(regex);
|
|
||||||
|
|
||||||
if (!matches || matches.length === 0) {
|
|
||||||
return {
|
|
||||||
isValid: false,
|
|
||||||
error: client.translate.get(language, "Events.messageCreate.noRoles")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const roles = matches.map(match => match.match(/{role:(.*?)}/)[1]);
|
|
||||||
|
|
||||||
if (roles.length > 20) {
|
|
||||||
return {
|
|
||||||
isValid: false,
|
|
||||||
error: client.translate.get(language, "Events.messageCreate.maxRoles")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return { isValid: true, roles };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds server roles by name
|
|
||||||
* @param {Array} roles - Array of role names
|
|
||||||
* @param {Object} server - Server object
|
|
||||||
* @returns {Object} Result containing found roles and unknown roles
|
|
||||||
*/
|
|
||||||
function findServerRoles(roles, server) {
|
|
||||||
const roleIds = roles.map(roleName =>
|
|
||||||
[...server.roles].find(([_, role]) =>
|
|
||||||
roleName.toLowerCase() === role.name.toLowerCase()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const unknown = roles.filter((_, index) => !roleIds[index]);
|
|
||||||
|
|
||||||
return { roleIds, unknown };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks for duplicate roles
|
|
||||||
* @param {Array} roleIds - Array of role IDs
|
|
||||||
* @returns {Array} Array of duplicate roles
|
|
||||||
*/
|
|
||||||
function findDuplicateRoles(roleIds) {
|
|
||||||
return roleIds.filter((role, index) =>
|
|
||||||
roleIds.findIndex(r => r[0] === role[0]) !== index
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks role positions against bot's role
|
|
||||||
* @param {Array} roleIds - Array of role IDs
|
|
||||||
* @param {Object} botRole - Bot's highest role
|
|
||||||
* @returns {Array} Array of roles with invalid positions
|
|
||||||
*/
|
|
||||||
function checkRolePositions(roleIds, botRole) {
|
|
||||||
return roleIds.filter(role => role[1].rank <= botRole.rank);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main collector function for message editing
|
|
||||||
* @param {Object} client - Discord client instance
|
|
||||||
* @param {Object} message - Message object
|
|
||||||
* @param {Object} db - Database object
|
|
||||||
*/
|
|
||||||
async function Collector(client, message, db) {
|
async function Collector(client, message, db) {
|
||||||
|
const regex = /{role:(.*?)}/;
|
||||||
|
const regexAll = /{role:(.*?)}/g;
|
||||||
const collector = client.messageEdit.get(message.authorId);
|
const collector = client.messageEdit.get(message.authorId);
|
||||||
|
if (!message.content.match(regexAll) || message.content.match(regexAll)?.length === 0) {
|
||||||
// Validate role mentions
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(`${client.translate.get(db.language, "Events.messageCreate.noRoles")}: \`{role:Red}\``)] }, false).catch(() => { return });
|
||||||
const validation = validateRoleMentions(message.content, db.language, client);
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
if (!validation.isValid) {
|
|
||||||
await message.reply({
|
|
||||||
embeds: [new Embed().setColor("#FF0000").setDescription(validation.error)]
|
|
||||||
}, false).catch(() => {});
|
|
||||||
return message.react(client.config.emojis.cross).catch(() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find server roles
|
const roles = message.content.match(regexAll).map((r) => r?.match(regex)[1]);
|
||||||
const { roleIds, unknown } = findServerRoles(validation.roles, message.server);
|
if (roles.length > 20) {
|
||||||
if (unknown.length > 0) {
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(client.translate.get(db.language, "Events.messageCreate.maxRoles"))] }, false).catch(() => { return });
|
||||||
await message.reply({
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
embeds: [new Embed().setColor("#FF0000").setDescription(
|
}
|
||||||
`${client.translate.get(db.language, "Events.messageCreate.unknown")}\n${
|
collector.regex = roles
|
||||||
unknown.map(e => `\`{role:${e}}\``).join(", ")
|
const roleIds = []
|
||||||
}`
|
let newRoles = roles.map((r) => {
|
||||||
)]
|
return [...message.server.roles].map((r) => r).find((role) => r.toLowerCase() === role[1]?.name?.toLowerCase());
|
||||||
}, false).catch(() => {});
|
})
|
||||||
return message.react(client.config.emojis.cross).catch(() => {});
|
newRoles.map((r) => roleIds.push(r));
|
||||||
|
|
||||||
|
if (roleIds.map((r) => !r).includes(true)) {
|
||||||
|
let unknown = [];
|
||||||
|
roleIds.map((r, i) => {
|
||||||
|
i++
|
||||||
|
if (!r) {
|
||||||
|
unknown.push(roles[i - 1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(`${client.translate.get(db.language, "Events.messageCreate.unknown")}\n${unknown.map(e => `\`{role:${e}}\``).join(", ")}`)] }, false).catch(() => { return });
|
||||||
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicates
|
let duplicate = [];
|
||||||
const duplicates = findDuplicateRoles(roleIds);
|
roleIds.map((r, i) => {
|
||||||
if (duplicates.length > 0) {
|
i++
|
||||||
await message.reply({
|
if (roleIds.filter(e => e[0] === r[0]).length > 1) duplicate.push(roleIds[i - 1]);
|
||||||
embeds: [new Embed().setColor("#FF0000").setDescription(
|
});
|
||||||
`${client.translate.get(db.language, "Events.messageCreate.duplicate")}\n${
|
|
||||||
duplicates.map(e => `\`{role:${e[1].name}}\``)
|
if (duplicate.length > 0) {
|
||||||
}`
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(`${client.translate.get(db.language, "Events.messageCreate.duplicate")}\n${duplicate.map(e => `\`{role:${e[1].name}}\``)}`)] }, false).catch(() => { return });
|
||||||
)]
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
}, false).catch(() => {});
|
|
||||||
return message.react(client.config.emojis.cross).catch(() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check role positions
|
let positions = [];
|
||||||
const botRole = message.channel.server.member.orderedRoles.reverse()[0];
|
const botRole = message.channel.server.member.orderedRoles.reverse()[0]
|
||||||
if (!botRole) {
|
if (!botRole) {
|
||||||
await message.reply({
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(client.translate.get(db.language, "Events.messageCreate.noBotRole"))] }, false).catch(() => { return });
|
||||||
embeds: [new Embed().setColor("#FF0000").setDescription(
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
client.translate.get(db.language, "Events.messageCreate.noBotRole")
|
|
||||||
)]
|
|
||||||
}, false).catch(() => {});
|
|
||||||
return message.react(client.config.emojis.cross).catch(() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const invalidPositions = checkRolePositions(roleIds, botRole);
|
roleIds.map((r, i) => {
|
||||||
if (invalidPositions.length > 0) {
|
i++
|
||||||
await message.reply({
|
if (r[1].rank <= botRole.rank) positions.push(roleIds[i - 1])
|
||||||
embeds: [new Embed().setColor("#FF0000").setDescription(
|
});
|
||||||
`${client.translate.get(db.language, "Events.messageCreate.positions")}\n${
|
|
||||||
invalidPositions.map(e => `\`{role:${e[1].name}}\``)
|
if (positions.length > 0) {
|
||||||
}`
|
message.reply({ embeds: [new Embed().setColor("#FF0000").setDescription(`${client.translate.get(db.language, "Events.messageCreate.positions")}\n${positions.map(e => `\`{role:${e[1].name}}\``)}`)] }, false).catch(() => { return });
|
||||||
)]
|
return message.react(client.config.emojis.cross).catch(() => { return });
|
||||||
}, false).catch(() => {});
|
|
||||||
return message.react(client.config.emojis.cross).catch(() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process valid message
|
message.delete().catch(() => { });
|
||||||
await message.delete().catch(() => {});
|
|
||||||
collector.roles = roleIds;
|
collector.roles = roleIds;
|
||||||
collector.regex = validation.roles;
|
|
||||||
|
|
||||||
const react = [client.config.emojis.check];
|
const react = [client.config.emojis.check];
|
||||||
const messageContent = collector.type === "content"
|
return message.channel.sendMessage(collector.type === "content" ? { content: message.content, interactions: [react] } : { embeds: [new Embed().setDescription(message.content).setColor("#A52F05")], interactions: [react] }).then((msg) => {
|
||||||
? { content: message.content, interactions: [react] }
|
|
||||||
: {
|
|
||||||
embeds: [new Embed().setDescription(message.content).setColor("#A52F05")],
|
|
||||||
interactions: [react]
|
|
||||||
};
|
|
||||||
|
|
||||||
const msg = await message.channel.sendMessage(messageContent);
|
|
||||||
collector.messageId = msg.id;
|
collector.messageId = msg.id;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Collector;
|
module.exports = Collector;
|
||||||
@ -1,104 +1,34 @@
|
|||||||
const path = require("path");
|
const PollDB = require("../models/polls");
|
||||||
const PollDB = require(path.join(__dirname, "../models/polls"));
|
const Embed = require("./embed");
|
||||||
const Embed = require(path.join(__dirname, "./embed"));
|
|
||||||
const Canvas = require('canvas');
|
const Canvas = require('canvas');
|
||||||
|
const format = `${(new Date().getMonth() + 1) < 10 ? `0${new Date().getMonth() + 1}` : new Date().getMonth() + 1}/${new Date().getDate()}/${new Date().getFullYear()} ${new Date().getHours()}:${(new Date().getMinutes() < 10 ? '0' : '') + new Date().getMinutes()}`;
|
||||||
// Constants
|
|
||||||
const CANVAS_CONFIG = {
|
|
||||||
WIDTH: 600,
|
|
||||||
PADDING: 10,
|
|
||||||
BAR_HEIGHT: 40,
|
|
||||||
FONT_SIZES: {
|
|
||||||
SMALL: '12px',
|
|
||||||
MEDIUM: '17px'
|
|
||||||
},
|
|
||||||
COLORS: {
|
|
||||||
BACKGROUND: "#23272A",
|
|
||||||
TEXT_PRIMARY: "#FFFFFF",
|
|
||||||
TEXT_SECONDARY: "#4E535A",
|
|
||||||
BAR_BACKGROUND: "#2C2F33",
|
|
||||||
BAR_FILL: "#A52F05",
|
|
||||||
BAR_INACTIVE: "#24282B",
|
|
||||||
SELECTION: "#717cf4"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper function to format date
|
|
||||||
const getFormattedDate = () => {
|
|
||||||
const now = new Date();
|
|
||||||
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
|
||||||
const day = now.getDate().toString().padStart(2, '0');
|
|
||||||
const hours = now.getHours().toString().padStart(2, '0');
|
|
||||||
const minutes = now.getMinutes().toString().padStart(2, '0');
|
|
||||||
return `${month}/${day}/${now.getFullYear()} ${hours}:${minutes}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Polls class for managing and rendering polls
|
|
||||||
*/
|
|
||||||
class Polls {
|
class Polls {
|
||||||
/**
|
constructor({ time, client, name, options, users, avatars, votes, owner, lang }) {
|
||||||
* @param {Object} options - Poll configuration options
|
|
||||||
* @param {number} options.time - Duration of the poll in milliseconds
|
|
||||||
* @param {Object} options.client - Discord client instance
|
|
||||||
* @param {Object} options.name - Poll name and description
|
|
||||||
* @param {Object} options.options - Poll options configuration
|
|
||||||
* @param {string[]} [options.users] - Array of user IDs who voted
|
|
||||||
* @param {string[]} [options.avatars] - Array of user avatar URLs
|
|
||||||
* @param {number[]} [options.votes] - Array of vote counts
|
|
||||||
* @param {string} options.owner - Poll owner ID
|
|
||||||
* @param {string} options.lang - Language code
|
|
||||||
*/
|
|
||||||
constructor({ time, client, name, options, users = [], avatars = [], votes, owner, lang }) {
|
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.time = time;
|
this.time = time;
|
||||||
this.owner = owner;
|
if (votes) this.votes = votes;
|
||||||
this.lang = lang;
|
else this.votes = options.name.length === 2 ? [0, 0] : options.name.length === 3 ? [0, 0, 0] : options.name.length === 4 ? [0, 0, 0, 0] : options.name.length === 5 ? [0, 0, 0, 0, 0] : options.name.length === 6 ? [0, 0, 0, 0, 0, 0] : options.name.length === 7 ? [0, 0, 0, 0, 0, 0, 0] : options.name.length === 8 ? [0, 0, 0, 0, 0, 0, 0, 0] : options.name.length === 9 ? [0, 0, 0, 0, 0, 0, 0, 0, 0] : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
this.users = users;
|
this.users = users || [];
|
||||||
this.avatars = avatars;
|
this.avatars = avatars || [];
|
||||||
this.options = { name: name.name, description: name.description };
|
this.options = { name: name.name, description: name.description };
|
||||||
this.voteOptions = options;
|
this.voteOptions = options;
|
||||||
|
this.owner = owner;
|
||||||
// Initialize votes array based on number of options
|
this.lang = lang;
|
||||||
this.votes = votes || new Array(options.name.length).fill(0);
|
this.size = { canvas: options.name.length === 2 ? 200 : options.name.length === 3 ? 250 : options.name.length === 4 ? 300 : options.name.length === 5 ? 350 : options.name.length === 6 ? 400 : options.name.length === 7 ? 450 : options.name.length === 8 ? 500 : options.name.length === 9 ? 550 : 600, bar: options.name.length === 2 ? 150 : options.name.length === 3 ? 200 : options.name.length === 4 ? 250 : options.name.length === 5 ? 300 : options.name.length === 6 ? 350 : options.name.length === 7 ? 400 : options.name.length === 8 ? 450 : options.name.length === 9 ? 500 : 550 };
|
||||||
|
|
||||||
// Calculate canvas dimensions based on number of options
|
|
||||||
this.size = this.calculateCanvasSize(options.name.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate canvas dimensions based on number of options
|
|
||||||
* @param {number} optionCount - Number of poll options
|
|
||||||
* @returns {Object} Canvas and bar dimensions
|
|
||||||
*/
|
|
||||||
calculateCanvasSize(optionCount) {
|
|
||||||
const baseSize = 200;
|
|
||||||
const increment = 50;
|
|
||||||
const size = baseSize + (optionCount - 2) * increment;
|
|
||||||
return {
|
|
||||||
canvas: size,
|
|
||||||
bar: size - 50
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the poll
|
|
||||||
* @param {Object} message - Discord message object
|
|
||||||
* @param {Object} poll - Poll instance
|
|
||||||
*/
|
|
||||||
async start(message, poll) {
|
async start(message, poll) {
|
||||||
this.client.polls.set(message.id, {
|
this.client.polls.set(message.id, { poll, messageId: message.id, users: this.users, owner: this.owner, lang: this.lang })
|
||||||
poll,
|
setTimeout(async () => {
|
||||||
messageId: message.id,
|
if (!this.client.polls.get(message.id)) return;
|
||||||
users: this.users,
|
await this.update();
|
||||||
owner: this.owner,
|
message.edit({ embeds: [new Embed().setMedia(await this.client.Uploader.upload(poll.canvas.toBuffer(), `Poll.png`)).setColor(`#F24646`)], content: this.client.translate.get(this.lang, "Functions.poll.end") }).catch(() => { })
|
||||||
lang: this.lang
|
this.client.polls.delete(message.id);
|
||||||
});
|
await PollDB.findOneAndDelete({ messageId: message.id });
|
||||||
|
}, this.time);
|
||||||
|
|
||||||
if (this.time < 0) return;
|
if (this.time < 0) return;
|
||||||
|
await (new PollDB({
|
||||||
// Save poll to database
|
|
||||||
await new PollDB({
|
|
||||||
owner: this.owner,
|
owner: this.owner,
|
||||||
channelId: message.channelId,
|
channelId: message.channelId,
|
||||||
messageId: message.id,
|
messageId: message.id,
|
||||||
@ -111,325 +41,208 @@ class Polls {
|
|||||||
time: this.time,
|
time: this.time,
|
||||||
lang: this.lang,
|
lang: this.lang,
|
||||||
now: Date.now(),
|
now: Date.now(),
|
||||||
}).save();
|
}).save());
|
||||||
|
|
||||||
// Set poll end timer
|
|
||||||
setTimeout(async () => {
|
|
||||||
if (!this.client.polls.get(message.id)) return;
|
|
||||||
|
|
||||||
await this.update();
|
|
||||||
const endMessage = this.client.translate.get(this.lang, "Functions.poll.end");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await message.edit({
|
|
||||||
embeds: [new Embed()
|
|
||||||
.setMedia(await this.client.Uploader.upload(poll.canvas.toBuffer(), 'Poll.png'))
|
|
||||||
.setColor('#F24646')],
|
|
||||||
content: endMessage
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to edit poll message:', error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client.polls.delete(message.id);
|
textHeight(text, ctx, m) {
|
||||||
await PollDB.findOneAndDelete({ messageId: message.id });
|
let metrics = m || ctx.measureText(text);
|
||||||
}, this.time);
|
return metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
roundRect(ctx, x, y, width, height, radius, fill, stroke) { // Credit to https://stackoverflow.com/users/227299/juan-mendes
|
||||||
* Calculate text height for canvas
|
if (typeof stroke === 'undefined') {
|
||||||
* @param {string} text - Text to measure
|
stroke = true;
|
||||||
* @param {CanvasRenderingContext2D} ctx - Canvas context
|
}
|
||||||
* @param {TextMetrics} [metrics] - Optional text metrics
|
if (typeof radius === 'undefined') {
|
||||||
* @returns {number} Text height
|
radius = 5;
|
||||||
*/
|
}
|
||||||
textHeight(text, ctx, metrics) {
|
if (typeof radius === 'number') {
|
||||||
const m = metrics || ctx.measureText(text);
|
radius = { tl: radius, tr: radius, br: radius, bl: radius };
|
||||||
return m.actualBoundingBoxAscent + m.actualBoundingBoxDescent;
|
} else {
|
||||||
|
var defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 };
|
||||||
|
for (var side in defaultRadius) {
|
||||||
|
radius[side] = radius[side] || defaultRadius[side];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw rounded rectangle on canvas
|
|
||||||
* @param {CanvasRenderingContext2D} ctx - Canvas context
|
|
||||||
* @param {number} x - X coordinate
|
|
||||||
* @param {number} y - Y coordinate
|
|
||||||
* @param {number} width - Rectangle width
|
|
||||||
* @param {number} height - Rectangle height
|
|
||||||
* @param {number|Object} radius - Corner radius
|
|
||||||
* @param {boolean} fill - Whether to fill the rectangle
|
|
||||||
* @param {boolean} stroke - Whether to stroke the rectangle
|
|
||||||
*/
|
|
||||||
roundRect(ctx, x, y, width, height, radius = 5, fill = true, stroke = true) {
|
|
||||||
const r = typeof radius === 'number'
|
|
||||||
? { tl: radius, tr: radius, br: radius, bl: radius }
|
|
||||||
: { tl: 0, tr: 0, br: 0, bl: 0, ...radius };
|
|
||||||
|
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(x + r.tl, y);
|
ctx.moveTo(x + radius.tl, y);
|
||||||
ctx.lineTo(x + width - r.tr, y);
|
ctx.lineTo(x + width - radius.tr, y);
|
||||||
ctx.quadraticCurveTo(x + width, y, x + width, y + r.tr);
|
ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
|
||||||
ctx.lineTo(x + width, y + height - r.br);
|
ctx.lineTo(x + width, y + height - radius.br);
|
||||||
ctx.quadraticCurveTo(x + width, y + height, x + width - r.br, y + height);
|
ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
|
||||||
ctx.lineTo(x + r.bl, y + height);
|
ctx.lineTo(x + radius.bl, y + height);
|
||||||
ctx.quadraticCurveTo(x, y + height, x, y + height - r.bl);
|
ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
|
||||||
ctx.lineTo(x, y + r.tl);
|
ctx.lineTo(x, y + radius.tl);
|
||||||
ctx.quadraticCurveTo(x, y, x + r.tl, y);
|
ctx.quadraticCurveTo(x, y, x + radius.tl, y);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
|
if (fill) {
|
||||||
if (fill) ctx.fill();
|
ctx.fill();
|
||||||
if (stroke) ctx.stroke();
|
}
|
||||||
|
if (stroke) {
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the poll canvas
|
|
||||||
*/
|
|
||||||
async update() {
|
async update() {
|
||||||
const { WIDTH, PADDING, BAR_HEIGHT, COLORS, FONT_SIZES } = CANVAS_CONFIG;
|
let roundRect = this.roundRect;
|
||||||
const height = this.size.canvas;
|
let textHeight = this.textHeight;
|
||||||
|
|
||||||
// Create canvas
|
var width = 600, height = this.size.canvas, padding = 10;
|
||||||
const canvas = Canvas.createCanvas(WIDTH, height);
|
const canvas = Canvas.createCanvas(width, height);
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
const ctx = this.canvas.getContext('2d');
|
const ctx = this.canvas.getContext('2d');
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
|
|
||||||
// Draw background
|
let name = this.options.name?.length > 70 ? this.options?.name.slice(0, 67) + "..." : this.options.name;
|
||||||
ctx.fillStyle = COLORS.BACKGROUND;
|
var nameHeight = textHeight(name, ctx);
|
||||||
this.roundRect(ctx, 0, 0, WIDTH, height, 5, true, false);
|
|
||||||
|
|
||||||
// Draw title and description
|
let description = this.options.description.length > 80 ? this.options.description.slice(0, 77) + "..." : this.options.description;
|
||||||
const name = this.truncateText(this.options.name, 70);
|
var descHeight = textHeight(description, ctx);
|
||||||
const description = this.truncateText(this.options.description, 80);
|
|
||||||
|
|
||||||
const nameHeight = this.textHeight(name, ctx);
|
ctx.fillStyle = "#23272A";
|
||||||
const descHeight = this.textHeight(description, ctx);
|
roundRect(ctx, 0, 0, width, height, 5, true, false); // background
|
||||||
|
|
||||||
// Draw title
|
ctx.fillStyle = "#4E535A";
|
||||||
ctx.fillStyle = COLORS.TEXT_SECONDARY;
|
ctx.font = `normal 12px Sans-Serif`;
|
||||||
ctx.font = `normal ${FONT_SIZES.SMALL} Sans-Serif`;
|
ctx.fillText(name, padding, padding + 2 + nameHeight / 2); // name
|
||||||
ctx.fillText(name, PADDING, PADDING + 2 + nameHeight / 2);
|
|
||||||
|
|
||||||
// Draw description
|
ctx.fillStyle = "#FFFFFF";
|
||||||
ctx.fillStyle = COLORS.TEXT_PRIMARY;
|
ctx.font = `normal 17px Sans-Serif`;
|
||||||
ctx.font = `normal ${FONT_SIZES.MEDIUM} Sans-Serif`;
|
ctx.fillText(description, padding, padding + 15 + nameHeight + descHeight / 2); // description
|
||||||
ctx.fillText(description, PADDING, PADDING + 15 + nameHeight + descHeight / 2);
|
|
||||||
|
|
||||||
const headerHeight = PADDING + descHeight + nameHeight + 15;
|
var headerHeight = padding + descHeight + nameHeight + 15;
|
||||||
const dataWidth = WIDTH - PADDING * 2;
|
var dataWidth = width - padding * 2;
|
||||||
|
var barHeight = 40;
|
||||||
|
var votes = this.votes;
|
||||||
|
var names = this.voteOptions.name;
|
||||||
|
|
||||||
// Draw vote bars
|
this.drawVoteBars(ctx, dataWidth - 20, barHeight, votes, { pad: padding, hHeight: headerHeight }, names);
|
||||||
this.drawVoteBars(ctx, dataWidth - 20, BAR_HEIGHT, this.votes,
|
await this.drawFooter(ctx, padding, padding + headerHeight + barHeight * 2 + 20, width, height, padding, this.avatars);
|
||||||
{ pad: PADDING, hHeight: headerHeight },
|
|
||||||
this.voteOptions.name);
|
|
||||||
|
|
||||||
// Draw footer
|
|
||||||
await this.drawFooter(ctx, PADDING, PADDING + headerHeight + BAR_HEIGHT * 2 + 20,
|
|
||||||
WIDTH, height, PADDING, this.avatars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Truncate text with ellipsis
|
|
||||||
* @param {string} text - Text to truncate
|
|
||||||
* @param {number} maxLength - Maximum length
|
|
||||||
* @returns {string} Truncated text
|
|
||||||
*/
|
|
||||||
truncateText(text, maxLength) {
|
|
||||||
return text?.length > maxLength ? text.slice(0, maxLength - 3) + "..." : text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a vote to the poll
|
|
||||||
* @param {number} option - Option index
|
|
||||||
* @param {string} user - User ID
|
|
||||||
* @param {string} avatar - User avatar URL
|
|
||||||
* @param {string} id - Message ID
|
|
||||||
* @returns {Canvas} Updated canvas
|
|
||||||
*/
|
|
||||||
async addVote(option, user, avatar, id) {
|
async addVote(option, user, avatar, id) {
|
||||||
if (this.avatars.length === 6) this.avatars.shift();
|
if (this.avatars.length === 6) this.avatars.shift();
|
||||||
this.avatars.push(avatar);
|
this.avatars.push(avatar);
|
||||||
this.votes[option]++;
|
this.votes[option]++;
|
||||||
|
await PollDB.findOneAndUpdate({ messageId: id }, { $push: { users: user, avatars: avatar }, $inc: { [`votes.${option}`]: 1 } });
|
||||||
await PollDB.findOneAndUpdate(
|
|
||||||
{ messageId: id },
|
|
||||||
{
|
|
||||||
$push: { users: user, avatars: avatar },
|
|
||||||
$inc: { [`votes.${option}`]: 1 }
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.update();
|
await this.update();
|
||||||
return this.canvas;
|
return this.canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a vote from the poll
|
|
||||||
* @param {number} option - Option index
|
|
||||||
* @param {string} user - User ID
|
|
||||||
* @param {string} avatar - User avatar URL
|
|
||||||
* @param {string} id - Message ID
|
|
||||||
* @returns {Canvas} Updated canvas
|
|
||||||
*/
|
|
||||||
async removeVote(option, user, avatar, id) {
|
async removeVote(option, user, avatar, id) {
|
||||||
this.avatars.splice(this.avatars.indexOf(avatar), 1);
|
this.avatars.splice(this.avatars.indexOf(avatar), 1);
|
||||||
this.votes[option]--;
|
this.votes[option]--;
|
||||||
|
await PollDB.findOneAndUpdate({ messageId: id }, { $pull: { users: user, avatars: avatar }, $inc: { [`votes.${option}`]: -1 } });
|
||||||
await PollDB.findOneAndUpdate(
|
|
||||||
{ messageId: id },
|
|
||||||
{
|
|
||||||
$pull: { users: user, avatars: avatar },
|
|
||||||
$inc: { [`votes.${option}`]: -1 }
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.update();
|
await this.update();
|
||||||
return this.canvas;
|
return this.canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw vote bars on canvas
|
|
||||||
* @param {CanvasRenderingContext2D} ctx - Canvas context
|
|
||||||
* @param {number} width - Bar width
|
|
||||||
* @param {number} height - Bar height
|
|
||||||
* @param {number[]} votes - Vote counts
|
|
||||||
* @param {Object} vars - Position variables
|
|
||||||
* @param {string[]} names - Option names
|
|
||||||
* @param {number} [vote] - Selected vote index
|
|
||||||
*/
|
|
||||||
drawVoteBars(ctx, width, height, votes, vars, names, vote) {
|
drawVoteBars(ctx, width, height, votes, vars, names, vote) {
|
||||||
const { PADDING, COLORS } = CANVAS_CONFIG;
|
let roundRect = this.roundRect;
|
||||||
const { pad: padding, hHeight: headerHeight } = vars;
|
let textHeight = this.textHeight;
|
||||||
|
let padding = vars.pad;
|
||||||
const sum = votes.reduce((prev, curr) => prev + curr, 0);
|
let headerHeight = vars.hHeight;
|
||||||
const percentages = votes.map(v => Math.floor(v / (sum / 100) * 10) / 10);
|
let sum = votes.reduce((prev, curr) => prev + curr);
|
||||||
|
let percentages = votes.map((v) => Math.floor(v / (sum / 100) * 10) / 10);
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(padding, padding + headerHeight);
|
ctx.translate(padding, padding + headerHeight);
|
||||||
|
|
||||||
const barPadding = 5;
|
var barPadding = 5;
|
||||||
percentages.forEach((percentage, i) => {
|
percentages.forEach((percentage, i) => {
|
||||||
const y = (height + 10) * i;
|
if (!percentage) percentage = 0;
|
||||||
const paddingLeft = vote !== undefined ? 30 : 0;
|
let paddingLeft = (vote != undefined) ? 30 : 0;
|
||||||
|
|
||||||
// Draw bar background
|
ctx.fillStyle = "#2C2F33";
|
||||||
ctx.fillStyle = COLORS.BAR_BACKGROUND;
|
let y = (height + 10) * i;
|
||||||
this.roundRect(ctx, 20, y, width, height, 5, true, false);
|
roundRect(ctx, 20, y, width, height, 5, true, false); // full bar
|
||||||
|
|
||||||
// Draw bar fill
|
if (vote == i || percentage) { ctx.fillStyle = "#A52F05"; }
|
||||||
ctx.fillStyle = (vote === i || percentage) ? COLORS.BAR_FILL : COLORS.BAR_INACTIVE;
|
else { ctx.fillStyle = "#24282B"; } // percentage display
|
||||||
this.roundRect(ctx, 20, y, width * (votes[i] / (sum / 100) / 100), height, 5, true, false);
|
roundRect(ctx, 20, y, width * (votes[i] / (sum / 100) / 100), height, 5, true, false);
|
||||||
|
|
||||||
// Draw option number
|
ctx.fillStyle = "#4E535A";
|
||||||
ctx.fillStyle = COLORS.TEXT_SECONDARY;
|
let h = textHeight(i + 1, ctx);
|
||||||
const numHeight = this.textHeight(i + 1, ctx);
|
ctx.fillText(i + 1, 0, y + height / 2 + h / 2);
|
||||||
ctx.fillText(i + 1, 0, y + height / 2 + numHeight / 2);
|
|
||||||
|
|
||||||
// Draw option name
|
ctx.fillStyle = "#FFFFFF"; // Option names
|
||||||
ctx.fillStyle = COLORS.TEXT_PRIMARY;
|
h = textHeight(names[i], ctx);
|
||||||
const name = this.truncateText(names[i], 65);
|
ctx.fillText(names[i].length > 65 ? names[i].slice(0, 62) + "..." : names[i], 30 + paddingLeft, y + 13 + h);
|
||||||
const nameHeight = this.textHeight(name, ctx);
|
|
||||||
ctx.fillText(name, 30 + paddingLeft, y + 13 + nameHeight);
|
|
||||||
|
|
||||||
// Draw selection circle if voting
|
if (vote != undefined) {
|
||||||
if (vote !== undefined) {
|
ctx.strokeStyle = "#FFFFFF"; // selection circle
|
||||||
ctx.strokeStyle = COLORS.TEXT_PRIMARY;
|
ctx.fillStyle = "#717cf4";
|
||||||
ctx.fillStyle = COLORS.SELECTION;
|
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(35, y + 10 + nameHeight * 0.75, 6, 0, 2 * Math.PI);
|
ctx.arc(35, y + 10 + h * 0.75, 6, 0, 2 * Math.PI);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
if (vote == i) {
|
||||||
if (vote === i) {
|
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(35, y + 10 + nameHeight * 0.75, 3, 0, 2 * Math.PI);
|
ctx.arc(35, y + 10 + h * 0.75, 3, 0, 2 * Math.PI);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw percentage and vote count
|
ctx.fillStyle = "#2C2F33"; // percentage and vote count background
|
||||||
const voteText = `${percentage}% (${votes[i]})`;
|
let metrics = ctx.measureText(percentage + "% (" + votes[i] + ")");
|
||||||
const metrics = ctx.measureText(voteText);
|
let w = metrics.width;
|
||||||
const textHeight = this.textHeight(voteText, ctx, metrics);
|
h = textHeight(percentage + "% (" + votes[i] + ")", ctx, metrics);
|
||||||
const textY = y + (height - textHeight - barPadding * 2) + barPadding * 2.6;
|
y = y + (height - h - barPadding * 2) + barPadding * 2.6;
|
||||||
|
if (vote == i || vote == undefined) roundRect(ctx, width - barPadding - w - 3, y - h - 4, w + 5, h + 12, 5, true, false);
|
||||||
|
|
||||||
if (vote === i || vote === undefined) {
|
ctx.fillStyle = "#A52F05"; // percentage and vote count
|
||||||
ctx.fillStyle = COLORS.BAR_BACKGROUND;
|
ctx.fillText(percentage + "% (" + votes[i] + ")", width - barPadding - w, y);
|
||||||
this.roundRect(ctx, width - barPadding - metrics.width - 3,
|
|
||||||
textY - textHeight - 4, metrics.width + 5, textHeight + 12, 5, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.fillStyle = COLORS.BAR_FILL;
|
|
||||||
ctx.fillText(voteText, width - barPadding - metrics.width, textY);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw footer on canvas
|
|
||||||
* @param {CanvasRenderingContext2D} ctx - Canvas context
|
|
||||||
* @param {number} x - X coordinate
|
|
||||||
* @param {number} y - Y coordinate
|
|
||||||
* @param {number} width - Canvas width
|
|
||||||
* @param {number} height - Canvas height
|
|
||||||
* @param {number} padding - Padding value
|
|
||||||
* @param {string[]} users - Array of user avatar URLs
|
|
||||||
*/
|
|
||||||
async drawFooter(ctx, x, y, width, height, padding, users) {
|
async drawFooter(ctx, x, y, width, height, padding, users) {
|
||||||
const { COLORS } = CANVAS_CONFIG;
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(10, this.size.bar);
|
ctx.translate(10, this.size.bar);
|
||||||
|
|
||||||
const rad = 18;
|
var rad = 18;
|
||||||
ctx.fillStyle = COLORS.TEXT_SECONDARY;
|
ctx.fillStyle = "#4E535A";
|
||||||
ctx.lineWidth = 2;
|
ctx.lineWidth = 2;
|
||||||
ctx.strokeStyle = COLORS.TEXT_SECONDARY;
|
ctx.strokeStyle = "#4E535A";
|
||||||
|
|
||||||
// Draw separator line
|
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(0 - padding, 0);
|
ctx.moveTo(0 - padding, 0);
|
||||||
ctx.lineTo(width, 0);
|
ctx.lineTo(width, 0);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
// Draw vote count
|
let votes = (this.votes.reduce((p, c) => p + c) == 1) ? `${this.votes.reduce((p, c) => p + c)} vote` : `${this.votes.reduce((p, c) => p + c)} votes`;
|
||||||
const totalVotes = this.votes.reduce((p, c) => p + c, 0);
|
let metrics = ctx.measureText(votes);
|
||||||
const voteText = totalVotes === 1 ? '1 vote' : `${totalVotes} votes`;
|
let h = this.textHeight(votes, ctx, metrics);
|
||||||
const metrics = ctx.measureText(voteText);
|
ctx.fillText(votes, 5, rad + h);
|
||||||
const textHeight = this.textHeight(voteText, ctx, metrics);
|
|
||||||
ctx.fillText(voteText, 5, rad + textHeight);
|
|
||||||
|
|
||||||
// Draw avatars
|
// Avatars
|
||||||
let pos = rad * users.length + 10 + metrics.width;
|
var pos = rad * users.length + 10 + metrics.width;
|
||||||
const yPos = 6;
|
var yPos = 6;
|
||||||
users.reverse();
|
users.reverse();
|
||||||
|
for (let i = 0; i < users.length; i++) {
|
||||||
|
ctx.beginPath();
|
||||||
|
let user = users[i];
|
||||||
|
|
||||||
for (const avatar of users) {
|
const a = Canvas.createCanvas(rad * 2, rad * 2);
|
||||||
const avatarCanvas = Canvas.createCanvas(rad * 2, rad * 2);
|
const context = a.getContext("2d");
|
||||||
const avatarCtx = avatarCanvas.getContext('2d');
|
|
||||||
|
|
||||||
avatarCtx.beginPath();
|
context.beginPath();
|
||||||
avatarCtx.arc(rad, rad, rad, 0, Math.PI * 2, true);
|
context.arc(rad, rad, rad, 0, Math.PI * 2, true);
|
||||||
avatarCtx.closePath();
|
context.closePath();
|
||||||
avatarCtx.clip();
|
context.clip();
|
||||||
|
|
||||||
try {
|
const avatar = await Canvas.loadImage(user);
|
||||||
const avatarImage = await Canvas.loadImage(avatar);
|
context.drawImage(avatar, 0, 0, rad * 2, rad * 2);
|
||||||
avatarCtx.drawImage(avatarImage, 0, 0, rad * 2, rad * 2);
|
ctx.drawImage(a, pos, yPos);
|
||||||
ctx.drawImage(avatarCanvas, pos, yPos);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to load avatar:', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ctx.closePath();
|
||||||
pos -= rad;
|
pos -= rad;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw date
|
// Date
|
||||||
const date = getFormattedDate();
|
let date = format;
|
||||||
const dateMetrics = ctx.measureText(date);
|
metrics = ctx.measureText(date);
|
||||||
const dateHeight = this.textHeight(date, ctx, dateMetrics);
|
h = this.textHeight(date, ctx, metrics);
|
||||||
ctx.fillText(date, width - 15 - dateMetrics.width, rad + dateHeight);
|
ctx.fillText(date, width - 15 - metrics.width, rad + h);
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
const crypt = require("crypto");
|
const crypt = require("crypto");
|
||||||
|
// const FlakeId = require('flakeid');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,109 +1,48 @@
|
|||||||
/**
|
|
||||||
* Reloads a module (event, function, or command) in the client
|
|
||||||
* @param {Object} client - The Discord client instance
|
|
||||||
* @param {string} category - The category of the module ('events', 'functions', or command name)
|
|
||||||
* @param {string} [name] - The name of the module (required for events and functions)
|
|
||||||
* @returns {string} Status message indicating success or failure
|
|
||||||
*/
|
|
||||||
function Reload(client, category, name) {
|
function Reload(client, category, name) {
|
||||||
// Input validation
|
if (category === "events") {
|
||||||
if (!client) throw new Error('Client instance is required');
|
if (!name) return 'Provide an event name to reload!'
|
||||||
if (!category) return 'Provide a category/command name to reload!';
|
try {
|
||||||
|
const evtName = name;
|
||||||
|
delete require.cache[require.resolve(`../events/${name}.js`)];
|
||||||
|
const pull = require(`../events/${name}`);
|
||||||
|
|
||||||
const reloaders = {
|
client.off(evtName, typeof client._events[evtName] == 'function' ? client._events[evtName] : client._events[evtName][0])
|
||||||
events: () => reloadEvent(client, name),
|
client.event.delete(evtName)
|
||||||
functions: () => reloadFunction(client, name),
|
|
||||||
default: () => reloadCommand(client, category)
|
|
||||||
};
|
|
||||||
|
|
||||||
return (reloaders[category] || reloaders.default)();
|
client.on(evtName, pull.bind(null, client))
|
||||||
}
|
client.event.set(evtName, pull.bind(null, client))
|
||||||
|
} catch (e) {
|
||||||
|
return `Couldn't reload: **${category}/${name}**\n**Error**: ${e.message}`
|
||||||
|
}
|
||||||
|
return `Reloaded event: **${name}**.js`
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
if (category === "functions") {
|
||||||
* Reloads an event module
|
if (!name) return 'Provide a function name to reload!'
|
||||||
* @param {Object} client - The Discord client instance
|
try {
|
||||||
* @param {string} name - The name of the event
|
const evtName = name;
|
||||||
* @returns {string} Status message
|
delete require.cache[require.resolve(`../functions/${name}.js`)];
|
||||||
*/
|
const pull = require(`../functions/${name}`);
|
||||||
function reloadEvent(client, name) {
|
|
||||||
if (!name) return 'Provide an event name to reload!';
|
client.functions.delete(evtName)
|
||||||
|
client.functions.set(evtName, pull)
|
||||||
|
} catch (e) {
|
||||||
|
return `Couldn't reload: **functions/${name}**\n**Error**: ${e.message}`
|
||||||
|
}
|
||||||
|
return `Reloaded function: **${name}**.js`
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const eventPath = `../events/${name}.js`;
|
if (!category) return 'Provide a command name to reload!'
|
||||||
delete require.cache[require.resolve(eventPath)];
|
delete require.cache[require.resolve(`../commands/${category}.js`)];
|
||||||
const eventModule = require(eventPath);
|
const pull = require(`../commands/${category}.js`);
|
||||||
|
if (client.commands.get(category).config.aliases) client.commands.get(category).config.aliases.forEach(a => client.aliases.delete(a));
|
||||||
// Remove existing event listener
|
client.commands.delete(category);
|
||||||
const existingHandler = client._events[name];
|
client.commands.set(category, pull);
|
||||||
if (existingHandler) {
|
if (client.commands.get(category).config.aliases) client.commands.get(category).config.aliases.forEach(a => client.aliases.set(a, category));
|
||||||
client.off(name, typeof existingHandler === 'function' ? existingHandler : existingHandler[0]);
|
return `Reloaded command: **commands/${category}**.js`
|
||||||
}
|
} catch (e) {
|
||||||
client.event.delete(name);
|
return `Couldn't reload: **commands/${category}**\n**Error**: ${e.message}`
|
||||||
|
|
||||||
// Add new event listener
|
|
||||||
const boundHandler = eventModule.bind(null, client);
|
|
||||||
client.on(name, boundHandler);
|
|
||||||
client.event.set(name, boundHandler);
|
|
||||||
|
|
||||||
return `Reloaded event: **${name}**.js`;
|
|
||||||
} catch (error) {
|
|
||||||
return `Couldn't reload: **events/${name}**\n**Error**: ${error.message}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reloads a function module
|
|
||||||
* @param {Object} client - The Discord client instance
|
|
||||||
* @param {string} name - The name of the function
|
|
||||||
* @returns {string} Status message
|
|
||||||
*/
|
|
||||||
function reloadFunction(client, name) {
|
|
||||||
if (!name) return 'Provide a function name to reload!';
|
|
||||||
|
|
||||||
try {
|
|
||||||
const functionPath = `../functions/${name}.js`;
|
|
||||||
delete require.cache[require.resolve(functionPath)];
|
|
||||||
const functionModule = require(functionPath);
|
|
||||||
|
|
||||||
client.functions.delete(name);
|
|
||||||
client.functions.set(name, functionModule);
|
|
||||||
|
|
||||||
return `Reloaded function: **${name}**.js`;
|
|
||||||
} catch (error) {
|
|
||||||
return `Couldn't reload: **functions/${name}**\n**Error**: ${error.message}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reloads a command module
|
|
||||||
* @param {Object} client - The Discord client instance
|
|
||||||
* @param {string} commandName - The name of the command
|
|
||||||
* @returns {string} Status message
|
|
||||||
*/
|
|
||||||
function reloadCommand(client, commandName) {
|
|
||||||
try {
|
|
||||||
const commandPath = `../commands/${commandName}.js`;
|
|
||||||
delete require.cache[require.resolve(commandPath)];
|
|
||||||
const commandModule = require(commandPath);
|
|
||||||
|
|
||||||
// Handle aliases
|
|
||||||
const existingCommand = client.commands.get(commandName);
|
|
||||||
if (existingCommand?.config?.aliases) {
|
|
||||||
existingCommand.config.aliases.forEach(alias => client.aliases.delete(alias));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update command
|
|
||||||
client.commands.delete(commandName);
|
|
||||||
client.commands.set(commandName, commandModule);
|
|
||||||
|
|
||||||
// Update aliases if they exist
|
|
||||||
if (commandModule.config?.aliases) {
|
|
||||||
commandModule.config.aliases.forEach(alias => client.aliases.set(alias, commandName));
|
|
||||||
}
|
|
||||||
|
|
||||||
return `Reloaded command: **commands/${commandName}**.js`;
|
|
||||||
} catch (error) {
|
|
||||||
return `Couldn't reload: **commands/${commandName}**\n**Error**: ${error.message}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,50 +1,12 @@
|
|||||||
const { readdirSync } = require("fs")
|
const { readdirSync } = require("fs")
|
||||||
const { join } = require("path")
|
|
||||||
const color = require("../functions/colorCodes")
|
const color = require("../functions/colorCodes")
|
||||||
|
module.exports = (client) => {
|
||||||
|
const commands = readdirSync(`./commands/`).filter(d => d.endsWith('.js'));
|
||||||
|
for (let file of commands) {
|
||||||
|
let pull = require(`../commands/${file}`);
|
||||||
|
client.commands.set(pull.config.name, pull);
|
||||||
|
if (pull.config.aliases) pull.config.aliases.forEach(a => client.aliases.set(a, pull.config.name));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
console.log(color("%", `%b[Command_Handler]%7 :: Loaded %e${client.commands.size} %7commands`));
|
||||||
* Loads and registers all command files from the commands directory
|
|
||||||
* @param {Object} client - The Discord client instance
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
module.exports = async (client) => {
|
|
||||||
try {
|
|
||||||
const commandsPath = join(__dirname, "..", "commands")
|
|
||||||
const commandFiles = readdirSync(commandsPath).filter(file => file.endsWith(".js"))
|
|
||||||
|
|
||||||
let loadedCommands = 0
|
|
||||||
let failedCommands = 0
|
|
||||||
|
|
||||||
for (const file of commandFiles) {
|
|
||||||
try {
|
|
||||||
const command = require(join(commandsPath, file))
|
|
||||||
|
|
||||||
// Validate command structure
|
|
||||||
if (!command.config?.name) {
|
|
||||||
console.error(color("%", `%r[Command_Handler]%7 :: Command in ${file} is missing required config.name property`))
|
|
||||||
failedCommands++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register command and aliases
|
|
||||||
client.commands.set(command.config.name, command)
|
|
||||||
if (command.config.aliases?.length) {
|
|
||||||
command.config.aliases.forEach(alias => client.aliases.set(alias, command.config.name))
|
|
||||||
}
|
|
||||||
|
|
||||||
loadedCommands++
|
|
||||||
} catch (error) {
|
|
||||||
console.error(color("%", `%r[Command_Handler]%7 :: Failed to load command ${file}: ${error.message}`))
|
|
||||||
failedCommands++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(color("%", `%b[Command_Handler]%7 :: Successfully loaded %e${loadedCommands}%7 commands`))
|
|
||||||
if (failedCommands > 0) {
|
|
||||||
console.warn(color("%", `%y[Command_Handler]%7 :: Failed to load %r${failedCommands}%7 commands`))
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(color("%", `%r[Command_Handler]%7 :: Critical error: ${error.message}`))
|
|
||||||
throw error // Re-throw to handle at higher level
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -1,24 +1,11 @@
|
|||||||
const { connect } = require("mongoose").set('strictQuery', true);
|
const { connect } = require("mongoose").set('strictQuery', true);
|
||||||
const color = require("../functions/colorCodes")
|
const color = require("../functions/colorCodes")
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
module.exports = class DatabaseHandler {
|
module.exports = class DatabaseHandler {
|
||||||
constructor(connectionString) {
|
constructor(connectionString) {
|
||||||
this.cache = new Map();
|
this.cache = new Map();
|
||||||
|
this.guildModel = require('../models/guilds');
|
||||||
this.connectionString = connectionString;
|
this.connectionString = connectionString;
|
||||||
this.models = {};
|
|
||||||
this.initializeModels();
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeModels() {
|
|
||||||
const modelsPath = path.join(__dirname, '../models');
|
|
||||||
const modelFiles = fs.readdirSync(modelsPath).filter(file => file.endsWith('.js'));
|
|
||||||
|
|
||||||
for (const file of modelFiles) {
|
|
||||||
const modelName = path.parse(file).name;
|
|
||||||
this.models[modelName] = require(path.join(modelsPath, file));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheSweeper(client) {
|
cacheSweeper(client) {
|
||||||
@ -59,17 +46,17 @@ module.exports = class DatabaseHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fetchGuild(guildId, createIfNotFound = false) {
|
async fetchGuild(guildId, createIfNotFound = false) {
|
||||||
const fetched = await this.models.guilds.findOne({ id: guildId });
|
const fetched = await this.guildModel.findOne({ id: guildId });
|
||||||
|
|
||||||
if (fetched) return fetched;
|
if (fetched) return fetched;
|
||||||
if (!fetched && createIfNotFound) {
|
if (!fetched && createIfNotFound) {
|
||||||
await this.models.guilds.create({
|
await this.guildModel.create({
|
||||||
id: guildId,
|
id: guildId,
|
||||||
language: 'en_EN',
|
language: 'en_EN',
|
||||||
botJoined: Date.now() / 1000 | 0,
|
botJoined: Date.now() / 1000 | 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.models.guilds.findOne({ id: guildId });
|
return this.guildModel.findOne({ id: guildId });
|
||||||
} return null;
|
} return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +78,7 @@ module.exports = class DatabaseHandler {
|
|||||||
async deleteGuild(guildId, onlyCache = false) {
|
async deleteGuild(guildId, onlyCache = false) {
|
||||||
if (this.cache.has(guildId)) this.cache.delete(guildId);
|
if (this.cache.has(guildId)) this.cache.delete(guildId);
|
||||||
|
|
||||||
return !onlyCache ? this.models.guilds.deleteMany({ id: guildId }) : true;
|
return !onlyCache ? this.guildModel.deleteMany({ id: guildId }) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateGuild(guildId, data = {}, createIfNotFound = false) {
|
async updateGuild(guildId, data = {}, createIfNotFound = false) {
|
||||||
@ -104,13 +91,13 @@ module.exports = class DatabaseHandler {
|
|||||||
|
|
||||||
this.cache.set(guildId, data);
|
this.cache.set(guildId, data);
|
||||||
|
|
||||||
return this.models.guilds.updateOne({
|
return this.guildModel.updateOne({
|
||||||
id: guildId,
|
id: guildId,
|
||||||
}, data);
|
}, data);
|
||||||
} return null;
|
} return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAll() {
|
async getAll() {
|
||||||
return this.models.guilds.find();
|
return this.guildModel.find();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1,44 +1,12 @@
|
|||||||
const { readdirSync } = require("fs")
|
const { readdirSync } = require("fs")
|
||||||
const path = require("path")
|
|
||||||
const color = require("../functions/colorCodes")
|
const color = require("../functions/colorCodes")
|
||||||
|
module.exports = (client) => {
|
||||||
|
const events = readdirSync(`./events/`).filter(d => d.endsWith('.js'));
|
||||||
|
for (let file of events) {
|
||||||
|
let evt = require(`../events/${file}`);
|
||||||
|
client.event.set(file.split(".")[0], evt.bind(null, client));
|
||||||
|
client.on(file.split('.')[0], evt.bind(null, client));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
console.log(color("%", `%b[Event_Handler]%7 :: Loaded %e${client.event.size} %7events`));
|
||||||
* Loads and registers all event handlers for the client
|
};
|
||||||
* @param {Object} client - The Discord client instance
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
module.exports = async (client) => {
|
|
||||||
try {
|
|
||||||
const eventsPath = path.join(__dirname, "..", "events")
|
|
||||||
const eventFiles = readdirSync(eventsPath)
|
|
||||||
.filter(file => file.endsWith(".js"))
|
|
||||||
|
|
||||||
const loadedEvents = await Promise.all(
|
|
||||||
eventFiles.map(async (file) => {
|
|
||||||
try {
|
|
||||||
const eventName = path.parse(file).name
|
|
||||||
const event = require(path.join(eventsPath, file))
|
|
||||||
|
|
||||||
// Register the event
|
|
||||||
client.event.set(eventName, event.bind(null, client))
|
|
||||||
client.on(eventName, event.bind(null, client))
|
|
||||||
|
|
||||||
return eventName
|
|
||||||
} catch (error) {
|
|
||||||
console.error(color("%", `%r[Event_Handler]%7 :: Failed to load event %e${file}%7: ${error.message}`))
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const successfulEvents = loadedEvents.filter(Boolean)
|
|
||||||
console.log(color("%", `%b[Event_Handler]%7 :: Successfully loaded %e${successfulEvents.length}%7 events`))
|
|
||||||
|
|
||||||
if (successfulEvents.length < eventFiles.length) {
|
|
||||||
console.warn(color("%", `%y[Event_Handler]%7 :: %r${eventFiles.length - successfulEvents.length}%7 events failed to load`))
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(color("%", `%r[Event_Handler]%7 :: Critical error: ${error.message}`))
|
|
||||||
throw error // Re-throw to handle it in the main application
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,40 +1,11 @@
|
|||||||
const { readdirSync } = require("fs")
|
const { readdirSync } = require("fs")
|
||||||
const { join } = require("path")
|
|
||||||
const logger = require("../functions/logger")
|
const logger = require("../functions/logger")
|
||||||
|
module.exports = (client) => {
|
||||||
|
const functions = readdirSync(`./functions`).filter(d => d.endsWith('.js'));
|
||||||
|
for (let file of functions) {
|
||||||
|
let evt = require(`../functions/${file}`);
|
||||||
|
client.functions.set(file.split(".")[0], evt);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
logger.event('Function_Handler', `Loaded ${client.functions.size} functions`);
|
||||||
* Loads and registers all function modules from the functions directory
|
|
||||||
* @param {Object} client - The client instance
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
module.exports = async (client) => {
|
|
||||||
try {
|
|
||||||
if (!client || !client.functions) {
|
|
||||||
throw new Error('Invalid client object or missing functions collection');
|
|
||||||
}
|
|
||||||
|
|
||||||
const functionsDir = join(__dirname, '..', 'functions');
|
|
||||||
const functions = readdirSync(functionsDir)
|
|
||||||
.filter(file => file.endsWith('.js') && file !== 'logger.js');
|
|
||||||
|
|
||||||
const loadedFunctions = await Promise.all(
|
|
||||||
functions.map(async (file) => {
|
|
||||||
try {
|
|
||||||
const functionName = file.split('.')[0];
|
|
||||||
const functionModule = require(join(functionsDir, file));
|
|
||||||
client.functions.set(functionName, functionModule);
|
|
||||||
return functionName;
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Function_Handler', `Failed to load function ${file}: ${error.message}`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const successfulLoads = loadedFunctions.filter(Boolean).length;
|
|
||||||
logger.event('Function_Handler', `Successfully loaded ${successfulLoads}/${functions.length} functions`);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Function_Handler', `Failed to initialize function handler: ${error.message}`);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
125
index.js
125
index.js
@ -2,102 +2,57 @@ const { Client } = require("revolt.js");
|
|||||||
const { Collection } = require('@discordjs/collection');
|
const { Collection } = require('@discordjs/collection');
|
||||||
const { token, mongoDB, api } = require("./botconfig.json");
|
const { token, mongoDB, api } = require("./botconfig.json");
|
||||||
const logger = require('./functions/logger');
|
const logger = require('./functions/logger');
|
||||||
const checkPolls = require('./functions/checkPolls');
|
const checkPolls = require('./functions/checkPolls')
|
||||||
|
|
||||||
const color = require("./functions/colorCodes");
|
const color = require("./functions/colorCodes");
|
||||||
|
|
||||||
|
const client = new Client({ baseURL: api });
|
||||||
const Uploader = require("revolt-uploader");
|
const Uploader = require("revolt-uploader");
|
||||||
|
const fetch = require("wumpfetch");
|
||||||
const TranslationHandler = require('./handlers/translation');
|
const TranslationHandler = require('./handlers/translation');
|
||||||
const DatabaseHandler = require('./handlers/database');
|
const DatabaseHandler = require('./handlers/database');
|
||||||
|
|
||||||
class Bot {
|
client.Uploader = new Uploader(client);
|
||||||
constructor(config) {
|
client.config = require("./config");
|
||||||
this.config = config;
|
client.translate = new TranslationHandler();
|
||||||
this.client = new Client({ baseURL: config.api });
|
client.logger = require('./functions/logger');
|
||||||
this.initializeCore();
|
client.botConfig = require("./botconfig.json");
|
||||||
this.initializeCollections();
|
|
||||||
this.setupErrorHandling();
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeCore() {
|
client.database = new DatabaseHandler(mongoDB);
|
||||||
this.client.Uploader = new Uploader(this.client);
|
client.database.connectToDatabase();
|
||||||
this.client.config = require("./config");
|
client.database.cacheSweeper(client);
|
||||||
this.client.translate = new TranslationHandler();
|
client.database.guildSweeper(client);
|
||||||
this.client.logger = logger;
|
|
||||||
this.client.botConfig = this.config;
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeCollections() {
|
["reactions", "paginate", "timeout", "polls", "used", "messageCollector", "messageEdit"].forEach(x => client[x] = new Map());
|
||||||
const collections = ["aliases", "commands", "event", "functions"];
|
["aliases", "commands", "event", "functions"].forEach(x => client[x] = new Collection());
|
||||||
const maps = ["reactions", "paginate", "timeout", "polls", "used", "messageCollector", "messageEdit"];
|
["command", "event", "function"].forEach(x => require(`./handlers/${x}`)(client));
|
||||||
|
|
||||||
collections.forEach(x => this.client[x] = new Collection());
|
client.once("ready", async () => {
|
||||||
maps.forEach(x => this.client[x] = new Map());
|
logger.success('Bot Ready', `${client.user.username} is ready`);
|
||||||
}
|
|
||||||
|
|
||||||
async initializeDatabase() {
|
//client.database.connectToDatabase();
|
||||||
try {
|
//client.database.cacheSweeper(client);
|
||||||
const db = new DatabaseHandler(this.config.mongoDB);
|
//client.database.guildSweeper(client);
|
||||||
await db.connectToDatabase();
|
|
||||||
|
|
||||||
this.client.database = db;
|
await checkPolls(client);
|
||||||
this.client.models = db.models;
|
|
||||||
|
|
||||||
db.cacheSweeper(this.client);
|
});
|
||||||
db.guildSweeper(this.client);
|
|
||||||
|
|
||||||
logger.success('Database', 'Successfully connected to database');
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Database Error', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setupErrorHandling() {
|
process.on("unhandledRejection", (reason, p) => {
|
||||||
const errorTypes = {
|
console.log(color("%", "%4[Error_Handling] :: Unhandled Rejection/Catch%c"));
|
||||||
"unhandledRejection": "Unhandled Rejection/Catch",
|
console.log(reason);
|
||||||
"uncaughtException": "Uncaught Exception/Catch",
|
console.log(p)
|
||||||
"uncaughtExceptionMonitor": "Uncaught Exception/Catch (MONITOR)"
|
});
|
||||||
};
|
process.on("uncaughtException", (err, origin) => {
|
||||||
|
console.log(color("%", "%4[Error_Handling] :: Uncaught Exception/Catch%c"));
|
||||||
|
console.log(err);
|
||||||
|
console.log(origin)
|
||||||
|
});
|
||||||
|
process.on("uncaughtExceptionMonitor", (err, origin) => {
|
||||||
|
console.log(color("%", "%4[Error_Handling] :: Uncaught Exception/Catch (MONITOR)%c"));
|
||||||
|
console.log(err);
|
||||||
|
console.log(origin)
|
||||||
|
});
|
||||||
|
|
||||||
Object.entries(errorTypes).forEach(([event, message]) => {
|
client.loginBot(token);
|
||||||
process.on(event, (error, origin) => {
|
|
||||||
logger.error('Error Handling', `${message}: ${error.message}`);
|
|
||||||
console.log(color("%", `%4[Error_Handling] :: ${message}%c`));
|
|
||||||
console.log(error);
|
|
||||||
if (origin) console.log(origin);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async initializeHandlers() {
|
|
||||||
try {
|
|
||||||
["command", "event", "function"].forEach(x => require(`./handlers/${x}`)(this.client));
|
|
||||||
logger.success('Handlers', 'Successfully initialized all handlers');
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Handler Error', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setupEventListeners() {
|
|
||||||
this.client.once("ready", async () => {
|
|
||||||
logger.success('Bot Ready', `${this.client.user.username} is ready`);
|
|
||||||
await checkPolls(this.client);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async start() {
|
|
||||||
try {
|
|
||||||
await this.initializeDatabase();
|
|
||||||
await this.initializeHandlers();
|
|
||||||
this.setupEventListeners();
|
|
||||||
await this.client.loginBot(this.config.token);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Startup Error', error);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the bot
|
|
||||||
const bot = new Bot({ token, mongoDB, api });
|
|
||||||
bot.start();
|
|
||||||
|
|||||||
10
package-lock.json
generated
10
package-lock.json
generated
@ -16,7 +16,7 @@
|
|||||||
"mongoose": "^7.2.0",
|
"mongoose": "^7.2.0",
|
||||||
"nanoid": "3.3.4",
|
"nanoid": "3.3.4",
|
||||||
"node-fetch-commonjs": "^3.3.2",
|
"node-fetch-commonjs": "^3.3.2",
|
||||||
"revolt-uploader": "^1.1.5",
|
"revolt-uploader": "^1.1.1",
|
||||||
"revolt.js": "npm:revolt.js-update@^7.0.0-beta.9",
|
"revolt.js": "npm:revolt.js-update@^7.0.0-beta.9",
|
||||||
"screen": "^0.2.10",
|
"screen": "^0.2.10",
|
||||||
"wumpfetch": "^0.3.1"
|
"wumpfetch": "^0.3.1"
|
||||||
@ -1227,10 +1227,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/revolt-uploader": {
|
"node_modules/revolt-uploader": {
|
||||||
"version": "1.1.6",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/revolt-uploader/-/revolt-uploader-1.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/revolt-uploader/-/revolt-uploader-1.1.4.tgz",
|
||||||
"integrity": "sha512-teMUhz/QJDqx/sXJFFReur8kR/KUSl2A5dYy9hLY/KLLgpaZw+el4bV+TgFb0vPtpM4hg7mLn44gLiuBR7kD7g==",
|
"integrity": "sha512-hnUCc1grg6Yq1J2q0HcsbfbWCvHIR6hPHzk3/75EjWEjP7bPYwAAVsHOwwtfdMtwMUPN9EAmBj3NvU4t+o1JJw==",
|
||||||
"license": "MIT",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"node-fetch": "^2.6.7"
|
"node-fetch": "^2.6.7"
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
"mongoose": "^7.2.0",
|
"mongoose": "^7.2.0",
|
||||||
"nanoid": "3.3.4",
|
"nanoid": "3.3.4",
|
||||||
"node-fetch-commonjs": "^3.3.2",
|
"node-fetch-commonjs": "^3.3.2",
|
||||||
"revolt-uploader": "^1.1.5",
|
"revolt-uploader": "^1.1.1",
|
||||||
"revolt.js": "npm:revolt.js-update@^7.0.0-beta.9",
|
"revolt.js": "npm:revolt.js-update@^7.0.0-beta.9",
|
||||||
"screen": "^0.2.10",
|
"screen": "^0.2.10",
|
||||||
"wumpfetch": "^0.3.1"
|
"wumpfetch": "^0.3.1"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user