Well that works
This commit is contained in:
parent
2050790f7a
commit
2f73c11435
2
.env.example
Normal file
2
.env.example
Normal file
|
@ -0,0 +1,2 @@
|
|||
BOT_TOKEN=YOUR_BOT_TOKEN
|
||||
DB_PATH=./database.db
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -130,3 +130,4 @@ dist
|
|||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
database.db
|
263
index.js
Normal file
263
index.js
Normal file
|
@ -0,0 +1,263 @@
|
|||
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);
|
5
migrations/1.sql
Normal file
5
migrations/1.sql
Normal file
|
@ -0,0 +1,5 @@
|
|||
-- Initialize database.
|
||||
CREATE TABLE IF NOT EXISTS guilds (
|
||||
id TEXT PRIMARY KEY,
|
||||
channel TEXT
|
||||
);
|
1637
package-lock.json
generated
Normal file
1637
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
18
package.json
Normal file
18
package.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"colors": "^1.4.0",
|
||||
"discord.js": "^14.15.3",
|
||||
"dotenv": "^16.4.5",
|
||||
"sqlite3": "^5.1.7"
|
||||
},
|
||||
"name": "invite-logger",
|
||||
"description": "A simple discord invite logger.",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "GPL-3.0-or-later"
|
||||
}
|
Loading…
Reference in a new issue