const https = require('node:https'); const fs = require('node:fs'); require('dotenv/config'); const { SlashCommandBuilder, MessageFlags, EmbedBuilder } = require('discord.js'); const { Tournament } = require("./data_objects/tournament.js"); const { tetrioRanks } = require("./data_objects/tetrio_ranks.js"); const xhr = { get: (uri) => { return new Promise((resolve, reject) => { https.get(uri, (res) => { const { statusCode } = res; const contentType = res.headers['content-type']; let error; // Any 2xx status code signals a successful response but // here we're only checking for 200. if (statusCode !== 200) { error = new Error('Request Failed.\n' + `Status Code: ${statusCode}`); } else if (!/^application\/json/.test(contentType)) { error = new Error('Invalid content-type.\n' + `Expected application/json but received ${contentType}`); } if (error) { console.error(error.message); // Consume response data to free up memory res.resume(); return; } res.setEncoding('utf8'); let rawData = ''; res.on('data', (chunk) => { rawData += chunk; }); res.on('end', () => { try { const parsedData = JSON.parse(rawData); if (parsedData.success) { resolve(parsedData); } else { reject(parsedData); } } catch (e) { reject(e.message); } }); }).on('error', (e) => { console.error(`Got error: ${e.message}`); }) }); }, }; async function reactionCheck(reaction, user, client, guild, teto, reg_role) { async function deny(embedTitle, embedReason) { reaction.users.remove(user.id); const exampleEmbed = new EmbedBuilder() .setColor(0xFF0000) .setTitle(embedTitle) .setDescription(embedReason) .setTimestamp(); const channel = await client.channels.cache.get(reaction.message.channelId); channel.send({ content: `<@${user.id}>`, embeds: [exampleEmbed] }).then(msg => { setTimeout(() => msg.delete(), 10000) }); } try { // Checking, if registration is open const current_time = Date.now()/1000; if(teto.unix_reg_end < current_time) {deny('Участники на данный турнир больше не принимаются', `Время на регистрацию истекло`); return} // Checking, if user has linked his TETR.IO account const search = await xhr.get(`https://ch.tetr.io/api/users/search/discord:${user.id}`); if (!search.success) { deny('Ваша регистрация отклонена', `По какой-то причине, бот не смог получить информацию о вашем профиле в TETR.IO`); return} if (!search.data) { deny('Ваша регистрация отклонена', `Вы не привязали этот Discord аккаунт к своему TETR.IO аккаунту.\n\n Чтобы это сделать, с главного меню TETR.IO перейдите в Config -> Account и проскролльте до самого конца`); return} // Trying to get data about the user const userData = await Promise.all([xhr.get(`https://ch.tetr.io/api/users/${search.data.user._id}`), xhr.get(`https://ch.tetr.io/api/users/${search.data.user._id}/summaries/league`)]); if (!userData[0].success || !userData[1].success){ // If we failed to do this deny('Ваша регистрация отклонена', `По какой-то причине, бот не смог получить информацию о вашем профиле в TETR.IO`); return} // Checking, if user is not banned if(userData[0].data.role === "banned"){ deny('Ваша регистрация отклонена', `Ваш аккаунт в TETR.IO забанен`); return} // Check for rank restricted events if user even have rank if((teto.rank_floor || teto.rank_roof) && (!userData[1].data.bestrank || userData[1].data.bestrank === "z")){ deny('Ваша регистрация отклонена', `Турнир имеет ограничения по рангу. У вас меньше 10 игр в Тетра Лиге и мы не можем понять, стоит ли вас пускать`); return} // Checking, if user's rank is higher, than rank floor if(teto.rank_floor && (tetrioRanks.indexOf(teto.rank_floor.toLowerCase()) > tetrioRanks.indexOf(userData[1].data.bestrank))){ deny('Ваша регистрация отклонена', `Ваш ранг слишком низкий для участия в данном турнире`); return} // Checking, if user's rank is lower, than rank roof if(teto.rank_roof && (tetrioRanks.indexOf(teto.rank_roof.toLowerCase()) < tetrioRanks.indexOf(userData[1].data.bestrank))){ deny('Ваша регистрация отклонена', `Ваш ранг слишком высокий для участия в данном турнире`); return} // Checking, if user is from CIS const cisCountries = ["RU", "BY", "AM", "AZ", "KZ", "KG", "MD", "TJ", "UZ", "TM", "UA"]; const { blacklist, whitelist } = require("./index.js"); if (!teto.international && (!cisCountries.includes(userData[0].data.country) || whitelist.includes(userData[0].data._id) || blacklist.includes(userData[0].data._id))){deny('Ваша регистрация отклонена', `${blacklist.includes(userData[0].data._id) ? "По данным, которые есть у нашей организации" : "Судя по вашему профилю в TETR.IO"}, вы не из СНГ`); return} // Finally, if everything is ok - add him to participants list teto.register(user.id, userData[0], userData[1]); guild.members.addRole({ user: user, reason: "Захотел участвовать", role: reg_role }); console.log(`${user.tag} registred for a ${teto.title} event`); } catch (error) { const check_in_channel = await client.channels.fetch(process.env.BOT_LOGS_CHANNEL); check_in_channel.send({ content: `Я поймал ошибку:\n\`${error}\`` }); return; } updateTournamentsJSON(); } async function unreactionCheck(reaction, user, guild, teto, reg_role) { guild.members.removeRole({ user: user, reason: "Расхотел участвовать", role: reg_role }); console.log(`${user.tag} unregistred for a ${teto.title} event`); teto.removeParticipant(user.id); updateTournamentsJSON(); } function updateTournamentsJSON(){ const { tournaments } = require('./index.js'); fs.writeFile('./tournaments.json', JSON.stringify(Object.fromEntries(tournaments)), err => { if (err) { console.error(err); } else { console.log("tournaments.json was updated"); } } ); } function updateWhitelistJSON(){ const { whitelist } = require('./index.js'); fs.writeFile('./whitelist.json', JSON.stringify([...whitelist]), err => { if (err) { console.error(err); } else { console.log("whitelist.json was updated"); } } ); } function updateBlacklistJSON(){ const { blacklist } = require('./index.js'); fs.writeFile('./blacklist.json', JSON.stringify([...blacklist]), err => { if (err) { console.error(err); } else { console.log("blacklist.json was updated"); } } ); } module.exports = { xhr, reactionCheck, unreactionCheck, updateTournamentsJSON, updateWhitelistJSON, updateBlacklistJSON }