invite-logger/index.js

263 lines
7.6 KiB
JavaScript

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
console.log(`Invite created: ${invite.code}`);
// 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;
}
console.log(row)
if (!row) return;
console.log(row.channel)
client.channels.fetch(row.channel).then(channel => {
console.log(channel.name)
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" : `<t:${invite.expiresTimestamp}>`
value: `Code: ${invite.code}\nMax Uses: ${invite.maxUses || "∞"}\nExpires <t:${Math.floor(new Date(invite.expiresAt) / 1000)}:R>\nCreated at: <t:${Math.floor(new Date(invite.createdAt) / 1000)}>`
},
{
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: <t:${Math.floor(new Date(member.joinedAt) / 1000)}>\nAccount Created: <t:${Math.floor(new Date(member.user.createdTimestamp) / 1000)}>`
},
{
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: <t:${Math.floor(new Date(invite.expiresAt) / 1000)}:R>\nCreated at: <t:${Math.floor(new Date(invite.createdAt) / 1000)}>`
},
{
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: <t:${Math.floor(new Date(member.joinedAt) / 1000)}>\nAccount Created: <t:${Math.floor(new Date(member.user.createdTimestamp) / 1000)}>`
},
{
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;
console.log(channel)
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);