const fs = require('fs'); const dotenv = require('dotenv'); dotenv.config(); const colors = require('colors'); const Discord = require('discord.js'); const client = new Discord.Client({ intents: [ "Guilds", "GuildMembers", "GuildInvites" ] }); const { REST, Routes } = require('discord.js'); const rest = new REST({ version: '10' }).setToken(process.env.BOT_TOKEN); const sqlite3 = require('sqlite3').verbose(); const db = new sqlite3.Database(process.env.DB_PATH); // DB migrations from files in ./migrations const migrations = fs.readdirSync('./migrations').sort(); migrations.forEach((migration) => { const sql = fs.readFileSync(`./migrations/${migration}`).toString(); // get first line for comment to log const comment = sql.split('\n')[0]; console.log(`${colors.cyan('INFO')} Running migration: ${colors.yellow(comment)}`); db.run(sql); }); // Handle bot ready client.on('ready', async () => { console.log(`${colors.cyan('INFO')} Logged in as ${colors.green(client.user.displayName)}!`); // Get all invites client.invites = []; // Update Invites client.guilds.cache.forEach(guild => { //on bot start, fetch all guilds and fetch all invites to store guild.invites.fetch().then(guildInvites => { guildInvites.each(guildInvite => { client.invites[guildInvite.code] = guildInvite.uses }) }) guild.fetchVanityData().then(vanityData => { client.invites[vanityData.code] = vanityData.uses }).catch(err => { // Do nothing }) }) // Register commands const commands = [ { name: "logchannel", description: "Set the channel to log invites", options: [ { name: "channel", description: "The channel to log invites to", type: 7, required: true } ], default_member_permissions: 32 } ] await (async () => { try { console.log(`${colors.cyan("[INFO]")} Registering Commands...`) let start = Date.now() //Global await rest.put(Routes.applicationCommands(client.user.id), { body: commands }) console.log(`${colors.cyan("[INFO]")} Successfully registered commands. Took ${colors.green((Date.now() - start) / 1000)} seconds.`); } catch (error) { console.error(error); } })(); }) // Handle invite creation client.on('inviteCreate', (invite) => { //if someone creates an invite while bot is running, update store client.invites[invite.code] = invite.uses // Check the db for the channel to log to, guild id is column `id` in table `guilds`, channel id is column `channel` db.get(`SELECT * FROM guilds WHERE id = ?`, [invite.guild.id], async (err, row) => { if (err) { console.error(err); return; } if (!row) return; client.channels.fetch(row.channel).then(channel => { if (!channel) return; // They probably set perms wrong channel.send({ embeds: [{ color: 0x00ffff, fields: [ { name: "New Invite", // inline check, if expiry is in over 100 years, then it's never, otherwise it's the date // ${invite.expiresTimestamp > 95617584000 ? "Never" : `` value: `Code: ${invite.code}\nMax Uses: ${invite.maxUses || "∞"}\nExpires \nCreated at: ` }, { name: "Guild", value: `${invite.guild.name}` }, { name: "Channel", value: `${invite.channel.name} <#${invite.channel.id}>` }, { name: "Inviter", value: `${invite.inviter} (${invite.inviter.username})` } ] }] }); }).catch(err => { console.log(`${colors.red('ERROR')} ${err.stack}`) }) }) }); // Handle new member client.on('guildMemberAdd', async (member) => { // We're just gonna always send invite logs, even if we're not monitoring them let guild = member.guild db.get(`SELECT * FROM guilds WHERE id = ?`, [guild.id], (err, row) => { if (err) { console.error(err); return; } if (!row) return; client.channels.fetch(row.channel.toString()).then(channel => { if (!channel) return; // They probably set perms wrong member.guild.invites.fetch().then(async guildInvites => { //get all guild invites guildInvites.forEach(invite => { //basically a for loop over the invites if (invite.uses != client.invites[invite.code]) { //if it doesn't match what we stored: channel.send({ embeds: [{ color: 0x00ff00, fields: [ { name: "New Member", value: `${member} (${member.user.displayName})\nJoined at: \nAccount Created: ` }, { name: "Invite", value: `Inviter: ${(invite.inviter.id == client.user.id) ? "Custom Invite URL (Through Bot)" : `${invite.inviter} (${invite.inviter.displayName})`}\nCode: ${invite.code}\nUses: ${invite.uses}/${invite.maxUses ||"∞"}\nExpires: \nCreated at: ` }, { name: "Guild", value: `${guild.name}` } ] }] }); client.invites[invite.code] = invite.uses } }) }) // Handle vanity URLs member.guild.fetchVanityData().then(vanityData => { if (vanityData.uses != client.invites[vanityData.code]) { // They used the vanity URL channel.send({ embeds: [{ color: 0x00ff00, fields: [ { name: "New Member", value: `${member} (${member.user.displayName})\nJoined at: \nAccount Created: ` }, { name: "Invite", value: `Vanity Code: ${vanityData.code}\nUses: ${vanityData.uses}` }, { name: "Guild", value: `${guild.name}` } ] }] }); } }).catch(err => { // Do nothing }) }) }); }) // Guild create client.on('guildCreate', async (guild) => { // Get invites guild.invites.fetch().then(guildInvites => { guildInvites.each(invite => { client.invites[invite.code] = invite.uses }) }) guild.fetchVanityData().then(vanityData => { client.invites[vanityData.code] = vanityData.uses }).catch(err => { // Do nothing }) }); // Guild delete client.on('guildDelete', async (guild) => { // Remove invites guild.invites.fetch().then(guildInvites => { guildInvites.each(invite => { delete client.invites[invite.code]; }) }) guild.fetchVanityData().then(vanityData => { delete client.invites[vanityData.code]; }).catch(err => { // Do nothing }) }); // Handle Commands client.on('interactionCreate', async interaction => { if (!interaction.isCommand()) return; if (interaction.commandName === 'logchannel') { if (!interaction.member.permissions.has('MANAGE_GUILD')) { interaction.reply({ content: "You do not have permission to use this command.", ephemeral: true }); return; } const channel = interaction.options.getChannel('channel').id; db.run(`INSERT OR REPLACE INTO guilds (id, channel) VALUES (?, ?)`, [interaction.guild.id.toString(), channel.toString()], (err) => { if (err) { console.error(err); interaction.reply({ content: "An error occurred while setting the log channel.", ephemeral: true }); return; } interaction.reply({ content: `The log channel has been set to <#${channel}>.`, ephemeral: true }); }); } }); client.login(process.env.BOT_TOKEN);