185 lines
8.0 KiB
JavaScript
185 lines
8.0 KiB
JavaScript
const fs = require('node:fs');
|
|
require('dotenv/config');
|
|
const path = require('node:path');
|
|
const { Client, Collection, Events, GatewayIntentBits, REST, Routes, MessageFlags, Partials, EmbedBuilder } = require('discord.js');
|
|
const { reactionCheck, unreactionCheck, updateTournamentsJSON } = require('./utils.js');
|
|
const { Tournament } = require('./data_objects/tournament.js');
|
|
|
|
function readTournamentsJSON() {
|
|
try {
|
|
const data = fs.readFileSync('./tournaments.json', { encoding: 'utf8' });
|
|
return new Map(Object.entries(JSON.parse(data)));
|
|
} catch (err) {
|
|
return new Map();
|
|
}
|
|
}
|
|
|
|
function readWhitelistJSON() {
|
|
try {
|
|
const data = fs.readFileSync('./whitelist.json', { encoding: 'utf8' });
|
|
return new Set(JSON.parse(data));
|
|
} catch (err) {
|
|
return new Set();
|
|
}
|
|
}
|
|
|
|
function readBlacklistJSON() {
|
|
try {
|
|
const data = fs.readFileSync('./blacklist.json', { encoding: 'utf8' });
|
|
return new Set(JSON.parse(data));
|
|
} catch (err) {
|
|
return new Set();
|
|
}
|
|
}
|
|
|
|
const tournaments = readTournamentsJSON();
|
|
const trackedTournaments = [];
|
|
const whitelist = readWhitelistJSON();
|
|
const blacklist = readBlacklistJSON();
|
|
|
|
module.exports = {
|
|
tournaments,
|
|
trackedTournaments,
|
|
blacklist,
|
|
whitelist
|
|
}
|
|
|
|
const client = new Client({
|
|
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions],
|
|
partials: [Partials.Message, Partials.Channel, Partials.Reaction, Partials.User],
|
|
}
|
|
);
|
|
|
|
client.commands = new Collection();
|
|
|
|
const foldersPath = path.join(__dirname, 'commands');
|
|
const commandFolders = fs.readdirSync(foldersPath);
|
|
|
|
for (const folder of commandFolders) {
|
|
const commandsPath = path.join(foldersPath, folder);
|
|
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
|
|
for (const file of commandFiles) {
|
|
const filePath = path.join(commandsPath, file);
|
|
const command = require(filePath);
|
|
// Set a new item in the Collection with the key as the command name and the value as the exported module
|
|
if ('data' in command && 'execute' in command) {
|
|
client.commands.set(command.data.name, command);
|
|
} else {
|
|
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
|
|
}
|
|
}
|
|
}
|
|
|
|
client.on('ready', () => {
|
|
console.log(`Logged in as ${client.user.tag}!`);
|
|
// Thing, that keeps track of clocks
|
|
setInterval(
|
|
() => {
|
|
let current_time = Date.now()/1000;
|
|
tournaments.forEach(async (value, key, map) => {
|
|
if (!trackedTournaments.find((element) => element === key) && value.status === 0 && value.unix_checkin_start > current_time && value.channelID && value.messageID){
|
|
// need to recheck for participants
|
|
const msg_channel = await client.channels.fetch(value.channelID);
|
|
const msg = await msg_channel.messages.fetch(value.messageID);
|
|
const collectorFilter = (reaction, user) => {
|
|
return reaction.emoji.name === '✅' && user.id !== msg.author.id;
|
|
};
|
|
tournaments.set(key, Tournament.fromObject(value));
|
|
// We gonna make sure, that user is eligible for a participation
|
|
const collector = msg.createReactionCollector({ filter: collectorFilter, time: value.unix_reg_end*1000 - current_time*1000, dispose: true });
|
|
collector.on('collect', async (reaction, user) => reactionCheck(reaction, user, client, msg_channel.guild, tournaments.get(key), value.participant_role));
|
|
collector.on('remove', async (reaction, user) => unreactionCheck(reaction, user, msg_channel.guild, tournaments.get(key), value.participant_role));
|
|
trackedTournaments.push(key);
|
|
}
|
|
if (value.status === 0 && value.unix_checkin_start < current_time) {
|
|
value.status = 1;
|
|
console.log("Check in started");
|
|
const checkInEmbed = new EmbedBuilder()
|
|
.setColor(0x00FF00)
|
|
.setTitle(value.title)
|
|
.setDescription(`Время подтверждать регистрацию\nКоличество регистрантов: ${value.participants.length}`)
|
|
.setFooter({ text: 'Поставьте ✅, чтобы подтвердить участие' })
|
|
.addFields(
|
|
{ name: "Завершение check in", value: `<t:${value.unix_checkin_end}:f>\n(<t:${value.unix_checkin_end}:R>)`},
|
|
{ name: "**Старт турнира**", value: `<t:${value.unix_start}:f>\n(<t:${value.unix_start}:R>)`},
|
|
);
|
|
const check_in_channel = await client.channels.fetch(value.channelID);
|
|
const check_in_message = await check_in_channel.send({ content: `<@&${value.participant_role}>`, embeds: [checkInEmbed] });
|
|
value.setCheckInMessageID()
|
|
const collectorFilter = (reaction, user) => {
|
|
return reaction.emoji.name === '✅' && user.id !== client.user.id;
|
|
};
|
|
check_in_message.react('✅');
|
|
// NOTE: only 24,855127314815 days max
|
|
const collector = check_in_message.createReactionCollector({ filter: collectorFilter, time: value.unix_checkin_end*1000 - current_time*1000, dispose: true });
|
|
collector.on('collect', async (reaction, user) => {
|
|
try{
|
|
if (value.check_in(user.id)){
|
|
check_in_message.guild.members.addRole({ user: user, reason: "Подтвердил участие", role: value.checked_in_role }); //h
|
|
console.log(`${user.tag} checked in for a ${value.title} event`);
|
|
}else{
|
|
reaction.users.remove(user.id);
|
|
const exampleEmbed = new EmbedBuilder()
|
|
.setColor(0xFF0000)
|
|
.setTitle("Вы не регистрировались на данный турнир")
|
|
.setDescription(value.unix_reg_end < current_time ? "Участники на данный турнир больше не принимаются" : "...но вы всё ещё можете зарегистрироваться!")
|
|
.setTimestamp();
|
|
check_in_channel.send({ content: `<@${user.id}>`, embeds: [exampleEmbed] }).then(msg => {
|
|
setTimeout(() => msg.delete(), 10000)
|
|
});
|
|
}
|
|
} catch (error) {
|
|
const check_in_channel = await client.channels.fetch(process.env.BOT_LOGS_CHANNEL);
|
|
check_in_channel.send({ content: `Я поймал ошибку:\n\`${error}\`` });
|
|
return;
|
|
}
|
|
updateTournamentsJSON();
|
|
});
|
|
|
|
collector.on('remove', async (reaction, user) => {
|
|
check_in_message.guild.members.addRole({ user: user, reason: "Расхотел участвовать", role: value.checked_in_role });
|
|
console.log(`${user.tag} unregistred for a ${value.title} event`);
|
|
value.removeChecked(user.id);
|
|
updateTournamentsJSON();
|
|
});
|
|
}
|
|
if (value.status === 1 && value.unix_checkin_end < current_time) {
|
|
value.status = 2;
|
|
console.log("Check in ended");
|
|
value.checked_in.sort((a, b) => b.tr - a.tr);
|
|
const checkInEmbed = new EmbedBuilder()
|
|
.setColor(0x0000FF)
|
|
.setTitle(`Check-in на ${value.title} завершен`)
|
|
.setDescription(`Количество участников: ${value.checked_in.length}\n\`${value.participants.map((element) => `${element.username.padEnd(18)}${Intl.NumberFormat("ru-RU", {minimumFractionDigits: 2, maximumFractionDigits: 2}).format(element.tr)} TR\n`)}\``)
|
|
.setFooter({ text: `Старт планировался в <t:${value.unix_start}:f> (<t:${value.unix_start}:R>)` });
|
|
const check_in_channel = await client.channels.fetch(process.env.RESULTS_CHANNEL);
|
|
check_in_channel.send({ embeds: [checkInEmbed] });
|
|
}
|
|
});
|
|
},
|
|
1000);
|
|
});
|
|
|
|
client.on(Events.InteractionCreate, async interaction => {
|
|
if (!interaction.isChatInputCommand()) return;
|
|
|
|
const command = interaction.client.commands.get(interaction.commandName);
|
|
|
|
if (!command) {
|
|
console.error(`No command matching ${interaction.commandName} was found.`);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await command.execute(interaction);
|
|
} catch (error) {
|
|
console.error(error);
|
|
if (interaction.replied || interaction.deferred) {
|
|
await interaction.followUp({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
|
|
} else {
|
|
await interaction.reply({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
|
|
}
|
|
}
|
|
});
|
|
|
|
client.login(process.env.DISCORD_TOKEN); |