modbot/index.js

244 lines
7.1 KiB
JavaScript

const config = require("./config.json");
const Discord = require("discord.js");
const colors = require("colors");
const sqlite3 = require("sqlite3").verbose();
const db = new sqlite3.Database("./database.db", (err) => {
if (err) {
console.error(`${colors.red("[ERROR]")} ${err.message}`);
}
console.log(`${colors.cyan("[INFO]")} DB Ready`);
db.run("CREATE TABLE IF NOT EXISTS actions (id INTEGER PRIMARY KEY AUTOINCREMENT, action TEXT, userid TEXT, username TEXT, reason TEXT, moderator TEXT, timestamp TEXT, expires TEXT, notes TEXT)");
});
const client = new Discord.Client({ intents: ["Guilds"] });
const {
REST,
Routes
} = require('discord.js');
const rest = new REST({
version: '10'
}).setToken(config.token);
client.on("ready", async () => {
console.log(`${colors.cyan("[INFO]")} Logged in as ${client.user.tag}`);
const commands = require("./commands.json");
await(async () => {
try {
//Global
await rest.put(Routes.applicationCommands(client.user.id), { body: commands }).then(() => {
console.log(`${colors.green("[SUCCESS]")} Global Commands registered`);
}).catch((error) => {
console.error(`${colors.red("[ERROR]")} ${error}`);
});
} catch (error) {
console.error(error);
}
})();
});
client.on("interactionCreate", async interaction => {
switch (interaction.type) {
case Discord.InteractionType.ApplicationCommand:
switch (interaction.commandName) {
case "log":
action = interaction.options.getString("action");
userid = interaction.options.getString("userid");
username = interaction.options.getString("username");
reason = interaction.options.getString("reason");
moderator = interaction.user.id;
timestamp = new Date();
expires = interaction.options.getString("duration");
notes = interaction.options.getString("notes");
// Start sanity checks
// Check if action is valid
if (!["warn", "mute", "kick", "ban"].includes(action)) {
await interaction.reply({
content: "Invalid action",
ephemeral: true
});
return;
}
// Check if userid is valid (SCPSL id, steam64@steam) \b[0-9]{17}@steam\b
if (!userid.match(/\b[0-9]{17}@steam\b/)) {
await interaction.reply({
content: "Invalid userid",
ephemeral: true
});
return;
}
// Check expires (format is Xm) X being a number m being m (minutes) h (hours) d (days) w (weeks) M (months) y (years)
if (!expires.match(/\b[0-9]{1,3}[mhdwMy]\b/)) {
await interaction.reply({
content: "Invalid expiry",
ephemeral: true
});
return;
}
// Convert expires to valid timestamp (like format above, that much time after current time)
expiry = new Date();
time = Number(expires.match(/\d+/)[0]);
unit = expires.match(/[mhdwMy]/)[0];
console.log(time)
console.log(unit)
switch (unit) {
case "m":
expiry.setMinutes(expiry.getMinutes() + time);
break;
case "h":
expiry.setHours(expiry.getHours() + time);
break;
case "d":
expiry.setDate(expiry.getDate() + time);
break;
case "w":
expiry.setDate(expiry.getDate() + time * 7);
break;
case "M":
expiry.setMonth(expiry.getMonth() + time);
break;
case "y":
expiry.setFullYear(expiry.getFullYear() + time);
break;
}
// Debug console log expiry
console.log(expiry.toTimeString());
console.log(new Date().toTimeString())
// Insert into database
db.run("INSERT INTO actions (action, userid, username, reason, moderator, timestamp, expires, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [action, userid, reason, moderator, timestamp, expiry, notes], async (err) => {
if (err) {
await interaction.reply({
content: "An error occured",
ephemeral: true
});
return;
}
// Send log to log channel
// Get log channel
logChannel = await client.channels.fetch(config.log_channel);
// Send log
logChannel.send({
embeds: [{
title: `New ${action}`,
fields: [
{
name: "Action",
value: action,
inline: true
},
{
name: "User ID",
value: userid,
inline: true
},
{
"name": "Username",
value: username || "No username provided",
inline: true
},
{
name: "Reason",
value: reason || "No reason provided",
inline: true
},
{
name: "Moderator",
value: `<@${moderator}>`
},
{
name: "Expires",
value: `<t:${Math.floor(expiry.getTime() / 1000)}:R> <t:${Math.floor(expiry.getTime() / 1000)}:f>`
},
{
name: "Notes",
value: notes || "No notes provided"
}
]
}]
})
await interaction.reply({
content: "Logged",
ephemeral: true
});
});
break;
case "get": // Get logs for specific IP or user ID
// Figure out if it's an IP or a user ID, then switch case it
target = interaction.options.getString("target");
if (target.match(/\b[0-9]{17}@steam\b/)) {
// sql limit 10 is ()
db.all("SELECT * FROM actions WHERE userid = ? LIMIT 10", [target], async (err, rows) => {
if (err) {
await interaction.reply({
content: "An error occured",
ephemeral: true
});
return;
}
if (rows.length == 0) {
await interaction.reply({
content: "No logs found",
ephemeral: true
});
return;
}
// Map rows to fields for embed
await interaction.reply({
content: `Last 10 entries for ID ${target}`,
embeds: [{
title: `Logs for ${target}`,
fields: rows.map(row => {
return {
name: `${row.action} - ${row.id}`,
value: `Reason: ${row.reason}\nModerator: <@${row.moderator}>\nTimestamp: <t:${Math.floor(new Date(row.timestamp) / 1000)}:r>\nExpires: ${row.expires}\nNotes: ${row.notes}`
}
})
}],
ephemeral: true
});
});
} else {
// Get logs for IP
db.all("SELECT * FROM actions WHERE ip LIKE ? LIMIT 10", [target + "%"], async (err, rows) => {
if (err) {
await interaction.reply({
content: "An error occured",
ephemeral: true
});
return;
}
if (rows.length == 0) {
await interaction.reply({
content: "No logs found",
ephemeral: true
});
return;
}
// Map rows to fields for embed
await interaction.reply({
content: `Last 10 entries for ${target}`,
embeds: [{
title: `Logs for ${target}`,
fields: rows.map(row => {
return {
name: `${row.action} - ${row.id}`,
value: `Reason: ${row.reason}\nModerator: <@${row.moderator}>\nTimestamp: ${row.timestamp}\nExpires: ${row.expires}\nNotes: ${row.notes}`
}
})
}],
ephemeral: true
});
});
}
break;
}
break;
}
});
client.login(config.token);