263 lines
7.7 KiB
JavaScript
263 lines
7.7 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}\n\`${invite.guild.id}\``
|
|
},
|
|
{
|
|
name: "Channel",
|
|
value: `${invite.channel.name}\n\`${invite.channel.id}\` <#${invite.channel.id}>`
|
|
},
|
|
{
|
|
name: "Inviter",
|
|
value: `${invite.inviter}\n\`${invite.inviter.id}\``
|
|
}
|
|
]
|
|
}]
|
|
});
|
|
}).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})\n\`${member.id}\`\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}\n\`${guild.id}\``
|
|
}
|
|
]
|
|
}]
|
|
});
|
|
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})\n\`${member.id}\`\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}\n\`${guild.id}\``
|
|
}
|
|
]
|
|
}]
|
|
});
|
|
}
|
|
}).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.id}>.`,
|
|
ephemeral: true
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
|
|
client.login(process.env.BOT_TOKEN); |