AstralMod/bot.js
reflectronic 3a717f41f2 Fixes Vol. 7
Warnings no longer spam the console
2019-01-21 18:50:16 -05:00

3989 lines
No EOL
151 KiB
JavaScript
Executable file
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************
*
* AstralMod: Moderation bot for bits & Bytes and other Discord servers
* Copyright (C) 2019 Victor Tran, John Tur
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* *************************************/
const Discord = require('discord.js');
const consts = require('./consts.js');
const fs = require('fs');
const readline = require('readline');
const events = require('events');
const blessed = require('blessed');
const moment = require('moment');
require("moment-duration-format");
const http = require('http');
const https = require('https');
const crypto = require('crypto');
const client = new Discord.Client({
restTimeOffset: 10,
disableEveryone: true
});
const i18next = require('i18next');
let i18nextbackend = require('i18next-node-fs-backend');
global.shutdown = () => {
if (global.settings != null) {
log("Saving settings...");
try {
var contents = JSON.stringify(settings, null, 4);
//Encrypt the contents
let iv = Buffer.from(crypto.randomBytes(16)).toString("hex").slice(0, 16);
var cipher = crypto.createCipheriv(cipherAlg, settingsKey, iv);
var settingsJson = Buffer.concat([cipher.update(Buffer.from(contents, "utf8"), cipher.final())]);
fs.writeFileSync("settings.json", settingsJson, "utf8");
fs.writeFileSync("iv", iv);
log("Settings saved!", logType.good);
} catch (exception) {
log("Settings couldn't be saved. You may lose some settings.", logType.critical);
}
}
log("Now exiting AstralMod.", logType.good);
client.user.setStatus("invisible").then((user) => {
// log(user.presence.status);
process.exit();
})
}
process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);
process.on("SIGQUIT", shutdown);
process.on("SIGHUP", shutdown);
global.prefix = (id) => {
if (id && settings && settings.guilds && settings.guilds[id] && settings.guilds[id].serverPrefix) {
return settings.guilds[id].serverPrefix;
}
return defaultPrefix;
}
if (process.argv.indexOf("--blueprint") == -1) {
global.amVersion = "3.0";
global.defaultPrefix = consts.config.prefix;
} else {
amVersion = "Blueprint";
global.defaultPrefix = consts.config.bprefix;
}
global.botOwner = undefined;
global.tempMods = {};
let doNotDeleteGuilds = [];
let availableTranslations = fs.readdirSync("translations");
availableTranslations.getTranslation = function(language) {
language = language.toLowerCase()
let aT = availableTranslations; //.map(t => t.toLowerCase());
if (aT.includes(language)) {
return language;
}
if (aT.filter(t => t.toLowerCase().startsWith(language)).length > 1) {
return null;
} else {
return aT.filter(t => t.toLowerCase().startsWith(language))[0];
}
};
i18next.use(i18nextbackend).init({
fallbackLng: ["en", false],
preload: availableTranslations,
ns: ["translation", "help"],
//saveMissing: true,
backend: {
loadPath: "./translations/{{lng}}/{{ns}}.json",
addPath: "./translations/{{lng}}/{{ns}}.json",
jsonIndent: 4
},
interpolation: {
format: function fmt(value, format, lng) {
if (value == null) return "[[[TRANSLATION ERROR]]]";
if (value.duration && moment.isDuration(value.duration)) {
//Special case for Chinese
if (lng.startsWith("zh")) lng = "zh-cn";
let m = value.duration.locale(lng);
if (format == "humanize") {
return m.humanize(value.prefixed);
} else {
return m.format(format, value.settings);
}
}
if (value.date instanceof Date || value.date instanceof moment) {
//maybe have different formats here later
//also take into account the user's 12/24h settings somehow at some point
//Special case for Chinese
if (lng.startsWith("zh")) lng = "zh-cn";
let m;
if (value.date instanceof moment) {
m = value.date.locale(lng);
} else {
m = moment.utc(value.date).locale(lng);
}
if (value.offset != null) {
m = m.utcOffset(value.offset);
}
if (format == "datetime") {
return arguments.callee(_[lng]("SPECIAL_DATETIME", { time: {date: m, h24: value.h24, offset: value.offset} }));
} else if (format == "date") {
return m.format("ddd MMM DD YYYY");
} else if (format == "time") {
if (value.h24) {
return m.format("HH:mm:ss");
} else {
return m.format("hh:mm:ss A");
}
} else if (format == "stime") {
if (value.h24) {
return m.format("HH:mm");
} else {
return m.format("hh:mm A");
}
} else {
return m.format(format);
}
}
if (format == "bold") return "**" + value + "**";
return value;
},
escapeValue: false
}
});
global._ = {
help: {}
};
for (let tr of availableTranslations) {
_[tr] = i18next.getFixedT(tr, "translation");
_.help[tr] = i18next.getFixedT(tr, "help");
}
global.tr = function() {
log("Warning: the tr function is being used", logType.warning);
return arguments[0];
}
const cipherAlg = "aes-256-ctr";
const sha256 = crypto.createHash("sha256");
const settingsKey = consts.keys.settingsKey.slice(0, 32);
const commandEmitter = new events.EventEmitter();
commandEmitter.setMaxListeners(100);
var plugins = {};
/** @type{Object} */
global.settings = null;
var listening = true;
var nickChanges = {};
var lockBox = [];
var banCounts = {};
var knownInvites = {};
var finalStdout = "";
global.banDescriptor = {};
let logFile = fs.createWriteStream("./log.log", {flags: 'a'});
logFile.write("\n\n-----NEW SESSION START-----\n");
logFile.write("ASTRALMOD " + amVersion + "\n");
global.UserInputError = function() {
var temp = Error.apply(this, arguments);
temp.name = "UserInputError";
this.name = "UserInputError";
this.message = temp.message;
}
UserInputError.prototype = Object.create(Error.prototype, {
constructor: {
value: UserInputError,
writable: true,
configurable: true
}
});
global.CommandError = function() {
var temp = Error.apply(this, arguments);
temp.name = "CommandError";
this.name = "CommandError";
this.message = temp.message;
}
CommandError.prototype = Object.create(Error.prototype, {
constructor: {
value: CommandError,
writable: true,
configurable: true
}
});
global.getRandom = function() {
if (arguments.length == 1) {
if (typeof arguments[0] == Array) {
var random = Math.floor(Math.random() * 1000) % arguments[0].length;
return arguments[0][random];
}
} else {
var random = Math.floor(Math.random() * 1000) % arguments.length;
return arguments[random];
}
}
global.filterOffensive = function(offensive) {
offensive = offensive.replace("shit", "s•••");
offensive = offensive.replace("fuck", "f•••");
return offensive;
}
global.getEmoji = function(emojiName) {
if (consts.config.emojiServer == null) return ":arrow_right:"; //No emoji server configured
try {
return client.guilds.get(consts.config.emojiServer).emojis.find(function(item) {
return item.name == emojiName;
}).toString();
} catch (err) {
return ":arrow_right:";
}
}
global.sendPreloader = function(text, channel) {
return channel.send(getEmoji("loader") + " " + text);
}
global.logType = {
debug: 0,
info: 1,
warning: 2,
critical: 3,
good: 4
}
var capture = {};
global.captureInput = function(func, guild, author) {
capture[guild] = {
function: func,
guild: guild,
author: author
};
}
global.releaseInput = function(guild) {
delete capture[guild];
}
global.unembed = function(embed) {
let embedString = "";
if (embed.author) embedString += `**${embed.author.name}**\n`;
if (embed.title) embedString += `**${embed.title}**\n`;
if (embed.description) embedString += `${embed.description}\n`;
for (let i in embed.fields) {
embedString += `\n**${embed.fields[i].name}**\n${embed.fields[i].value}\n`
}
if (embed.footer) embedString += `\n${embed.footer.text}`
return embedString || $("PINS_EMPTY_EMBED"); //returns a string
}
global.awaitUserConfirmation = function(options) {
let $ = _[options.locale];
return new Promise(function(resolve, reject) {
if (options.time == null || options.time < 1) options.time = 5; //Default to 5 seconds
let embed = new Discord.RichEmbed();
embed.setTitle(options.title);
embed.setDescription(options.msg);
embed.setColor(consts.colors.info);
embed.setFooter($("AWAITUSERCONFIRMATION_CANCEL_PROMPT", {emoji: "🚫", time: options.time}));
if (options.extraFields != null) {
for (let field in options.extraFields) {
let currentField = options.extraFields[field];
embed.addField(currentField[0], currentField[1]);
}
}
options.channel.send(embed).then(function(message) {
message.react('🚫');
let timeout = setTimeout(function() {
if (!options.doNotClear)
message.clearReactions();
else {
for (let [, reaction] of message.reactions) {
reaction.remove().catch(() => { });
}
}
if (options.msgOnSuccess != "") {
embed.setDescription(options.msgOnSuccess);
}
embed.fields = [];
embed.setColor(consts.colors.done);
embed.setFooter($("AWAITUSERCONFIRMATION_FULFILLED"));
message.edit(embed);
resolve();
}, options.time * 1000);
message.awaitReactions(function(reaction) {
if (reaction.count > 1 && reaction.users.has(options.author.id)) return true;
return false;
}, {
max: 1
}).then(function() {
//Cancel the function
clearTimeout(timeout);
if (!options.doNotClear)
message.clearReactions();
else {
for (let [, reaction] of message.reactions) {
reaction.remove().catch(() => { });
}
}
if (options.msgOnFail != "") {
embed.setDescription(options.msgOnFail);
}
embed.fields = [];
embed.setColor(consts.colors.fail);
embed.setFooter($("AWAITUSERCONFIRMATION_CANCELLED"));
message.edit(embed);
reject();
});
});
});
}
//Set up screen
var screen = blessed.screen({
smartCSR: true,
dockBorders: true
});
screen.title = 'AstralMod ' + amVersion;
var titleBox = blessed.text({
top: "0",
left: "0",
width: "100%",
height: "1",
content: "AstralMod " + amVersion + " Console",
tags: true,
style: {
fg: 'black',
bg: 'white'
},
padding: {
left: 1
}
});
screen.append(titleBox);
var logBox = blessed.log({
top: 1,
left: 0,
width: "100%",
height: "100%-4",
tags: true,
style: {
fg: 'white',
bg: 'black',
scrollbar: {
bg: 'white'
}
},
padding: {
left: 1 // ,
// bottom: 2
},
scrollable: true,
alwaysScroll: true,
scrollOnInput: true,
scrollbar: true //,
//clickable: true
});
screen.append(logBox);
function clearBoxes() {
while (lockBox.length > 0) {
var box = lockBox.pop();
box.hide();
box.destroy();
}
}
logBox.on('click', function(mouse) {
var x = mouse.x;
var y = mouse.y;
//var line = logBox.getScreenLines()[y + 1];
var line = logBox.getBaseLine(y - 1);
//Remove escapes
while (line.indexOf("\x1b") != -1) {
var removeStart = line.indexOf("\x1b");
var removeEnd = line.indexOf("m", removeStart);
line = line.replace(line.slice(removeStart, removeEnd + 1), "");
}
//logBox.log(line);
//Get word around line
var previousSpace = line.lastIndexOf(" ", x - 2);
var nextSpace = line.indexOf(" ", x - 2);
previousSpace++;
if (nextSpace == -1) {
nextSpace = line.length;// - previousSpace;
}
var word = line.substring(previousSpace, nextSpace);
if (word.startsWith("[")) word = word.substr(1);
if (word.endsWith("]")) word = word.substr(0, word.length - 2);
var goUpwards = false;
var top = y + 1;
if (top + 7 > screen.height) {
top = y - 7;
goUpwards = true;
}
var left = x - 10;
if (left + 50 > screen.width) {
left = screen.width - 50;
} else if (left < 0) {
left = 0;
}
var boxOptions = {
top: top,
left: left,
width: 50,
style: {
fg: "black",
bg: "white",
border: {
fg: 'white',
bg: 'black'
}
},
border: {
type: "line"
},
padding: {
left: 2,
top: 1,
right: 2,
bottom: 1
}
};
clearBoxes();
//Determine type of object clicked
if (client.guilds.has(word)) {
//This is a guild
var guild = client.guilds.get(word);
var box = blessed.box(JSON.parse(JSON.stringify(boxOptions)));
box.content = "For Guild " + word + "\n" +
"Name: " + guild.name;
box.height = 7;
screen.append(box);
if (goUpwards) {
boxOptions.top -= 6;
} else {
boxOptions.top += 6;
}
var moreInfoButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
}
});
moreInfoButton.content = "More Info";
moreInfoButton.left = 0;
moreInfoButton.top = 2;
moreInfoButton.width = 9;
moreInfoButton.height = 1;
moreInfoButton.on('click', function() {
clearBoxes();
renderScreen();
processConsoleInput("ginfo " + word);
});
box.append(moreInfoButton);
var membersButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
}
});
membersButton.content = "Members";
membersButton.left = 10;
membersButton.top = 2;
membersButton.width = 7;
membersButton.height = 1;
membersButton.on('click', function() {
clearBoxes();
renderScreen();
processConsoleInput("ginfom " + word);
});
box.append(membersButton);
var channelsButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
}
});
channelsButton.content = "Channels";
channelsButton.left = 18;
channelsButton.top = 2;
channelsButton.width = 8;
channelsButton.height = 1;
channelsButton.on('click', function() {
clearBoxes();
renderScreen();
processConsoleInput("ginfoc " + word);
});
box.append(channelsButton);
var bansButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
}
});
bansButton.content = "Bans";
bansButton.left = 27;
bansButton.top = 2;
bansButton.width = 4;
bansButton.height = 1;
bansButton.on('click', function() {
clearBoxes();
renderScreen();
processConsoleInput("ginfob " + word);
});
box.append(bansButton);
lockBox.push(box);
}
if (client.channels.has(word)) {
//This is a channel
var channel = client.channels.get(word);
var box = blessed.box(JSON.parse(JSON.stringify(boxOptions)));
box.content = "For Channel " + word + "\n" +
"Name: " + channel.name;
box.height = 7;
screen.append(box);
if (goUpwards) {
boxOptions.top -= 6;
} else {
boxOptions.top += 6;
}
var moreInfoButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
}
});
moreInfoButton.content = "More Info";
moreInfoButton.left = 0;
moreInfoButton.top = 2;
moreInfoButton.width = 9;
moreInfoButton.height = 1;
moreInfoButton.on('click', function() {
clearBoxes();
renderScreen();
processConsoleInput("cinfo " + word);
});
box.append(moreInfoButton);
var sendButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
}
});
sendButton.content = "Send";
sendButton.left = 10;
sendButton.top = 2;
sendButton.width = 4;
sendButton.height = 1;
sendButton.on('click', function() {
clearBoxes();
renderScreen();
//processConsoleInput("cinfo " + word);
showTextBox();
textBox.setValue("> send " + word + " ");
renderScreen();
});
box.append(sendButton);
lockBox.push(box);
}
if (client.users.has(word)) {
//This is a user
var user = client.users.get(word);
var box = blessed.box(JSON.parse(JSON.stringify(boxOptions)));
box.content = "For User " + word + "\n" +
"Name: " + user.username;
box.height = 7;
screen.append(box);
if (goUpwards) {
boxOptions.top -= 6;
} else {
boxOptions.top += 6;
}
lockBox.push(box);
}
if (plugins.hasOwnProperty(word)) {
//This is a plugin
var plugin = plugins[word];
var box = blessed.box(JSON.parse(JSON.stringify(boxOptions)));
box.content = "For Plugin \"" + plugin.name + "\"\n" +
"Filename: " + word;
box.height = 7;
screen.append(box);
if (goUpwards) {
boxOptions.top -= 6;
} else {
boxOptions.top += 6;
}
var unloadButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
}
});
unloadButton.content = "Unload";
unloadButton.left = 0;
unloadButton.top = 2;
unloadButton.width = 6;
unloadButton.height = 1;
unloadButton.on('click', function() {
clearBoxes();
renderScreen();
processConsoleInput("unload " + word);
});
box.append(unloadButton);
var reloadButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
}
});
reloadButton.content = "Reload";
reloadButton.left = 7;
reloadButton.top = 2;
reloadButton.width = 6;
reloadButton.height = 1;
reloadButton.on('click', function() {
clearBoxes();
renderScreen();
processConsoleInput("reload " + word);
});
box.append(reloadButton);
lockBox.push(box);
}
if (word == "save" || word == "plugins" || word == "vacuum" || word == "guilds" || word == "exit") {
processConsoleInput(word);
}
screen.render();
});
var textBox = blessed.textbox({
top: "100%-3",
left: -1,
width: "100%+2",
height: 3,
tags: true,
value: "> ",
border: {
type: "line"
},
style: {
fg: 'white',
bg: 'black',
border: {
fg: 'white',
bg: 'black'
}
},
inputOnFocus: true
});
screen.append(textBox);
var keyBox = blessed.box({
top: "100%-1",
left: "0",
width: "100%",
height: 1,
tags: true,
style: {
fg: 'black',
bg: 'white'
},
padding: {
left: 1
}
});
screen.append(keyBox);
var guildsButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
},
content: "^G Guilds",
left: 10,
width: 9,
height: 1,
top: "100%-1"
});
guildsButton.on('click', function() {
processConsoleInput("guilds");
});
screen.append(guildsButton);
var pluginsButton = blessed.button({
style: {
fg: "yellow",
bg: "blue"
},
content: "^P Plugins",
left: 20,
width: 10,
height: 1,
top: "100%-1"
});
pluginsButton.on('click', function() {
processConsoleInput("plugins");
});
screen.append(pluginsButton);
textBox.key('C-c', function(ch, key) {
shutdown();
});
screen.key('C-c', function() {
shutdown();
});
screen.key('C-g', function() {
processConsoleInput("guilds");
});
screen.key('C-p', function() {
processConsoleInput("plugins");
});
screen.key('up', function() {
logBox.scroll(-1);
renderScreen();
});
screen.on('keypress', function(key) {
if (lockBox.length != 0) {
clearBoxes();
} else if (key != undefined && !textBox.focused && key != "\r") {
showTextBox();
if (key != ":") {
textBox.setValue("> " + key);
}
}
});
screen.key('pageup', function() {
logBox.scroll(-logBox.height);
renderScreen();
});
screen.key('down', function() {
logBox.scroll(1);
renderScreen();
});
screen.key('pagedown', function() {
logBox.scroll(logBox.height);
renderScreen();
});
function showTextBox() {
logBox.height = "100%-4";
keyBox.content = "ESC Cancel Command ENTER Issue Command";
textBox.show();
textBox.focus();
guildsButton.hide();
pluginsButton.hide();
renderScreen();
}
var currentHistoryEntry = -1;
function hideTextBox() {
textBox.setValue("> ");
logBox.height = "100%-2";
keyBox.content = "^C Exit To issue a command, just start typing away.";
textBox.hide();
logBox.focus();
guildsButton.show();
pluginsButton.show();
currentHistoryEntry = -1;
renderScreen();
}
textBox.key("up", function() {
currentHistoryEntry++;
if (commandHistory[currentHistoryEntry] != null) {
textBox.setValue("> " + commandHistory[currentHistoryEntry]);
} else {
currentHistoryEntry = -1;
textBox.setValue("> ");
}
renderScreen();
});
textBox.key("down", function() {
currentHistoryEntry--
if (commandHistory[currentHistoryEntry] != null) {
textBox.setValue("> " + commandHistory[currentHistoryEntry]);
} else {
currentHistoryEntry = -1;
textBox.setValue("> ");
}
renderScreen();
});
textBox.on("cancel", function() {
hideTextBox();
});
function renderScreen() {
screen.render();
}
renderScreen();
hideTextBox();
console.error = function(data, ...args){
log(data, logType.warning);
};
global.log = function(logMessage, type = logType.debug) {
if (logMessage == null) {
return;
}
if (logMessage instanceof Error) {
logMessage = logMessage.toString() + "\n" + logMessage.stack;
} else {
logMessage = logMessage.toString();
}
//Log a message to the console
if (type == logType.debug) {
if (process.argv.indexOf("--debug") == -1) {
return;
}
}
var logFormatting;
var logString;
var lines = logMessage.split("\n");
for (i = 0; i < lines.length; i++) {
switch (type) {
case logType.debug:
if (i == 0) {
logString = "[ ] ";
} else if (i == lines.length - 1) {
logString = " └─ ";
} else {
logString = " ├─ ";
}
logString += lines[i];
logFormatting = "\x1b[1m\x1b[34m";
break;
case logType.info:
if (i == 0) {
logString = "[i] ";
} else if (i == lines.length - 1) {
logString = " └─ ";
} else {
logString = " ├─ ";
}
logString += lines[i];
logFormatting = "\x1b[1m\x1b[37m";
break;
case logType.warning:
if (i == 0) {
logString = "[!] ";
} else if (i == lines.length - 1) {
logString = " └─ ";
} else {
logString = " ├─ ";
}
logString += lines[i];
logFormatting = "\x1b[1m\x1b[33m";
break;
case logType.critical:
if (i == 0) {
logString = "[X] ";
} else if (i == lines.length - 1) {
logString = " └─ ";
} else {
logString = " ├─ ";
}
logString += lines[i];
logFormatting = "\x1b[1m\x1b[31m";
break;
case logType.good:
if (i == 0) {
logString = "[>] ";
} else if (i == lines.length - 1) {
logString = " └─ ";
} else {
logString = " ├─ ";
}
logString += lines[i];
logFormatting = "\x1b[1m\x1b[32m";
break;
}
var logOutput = logFormatting + logString + "\x1b[0m";
logBox.log("[" + new Date().toLocaleTimeString("us", {
hour12: false
}) + "] " + logOutput);
logFile.write("[" + new Date().toLocaleTimeString("us", {
hour12: false
}) + "] " + logString + "\n");
renderScreen();
}
}
global.logPromiseRejection = function(object, action) {
log("Couldn't delete message " + object.id + " in channel " + object.channel.id, logType.warning);
};
// HACK HACK HACK HACK
// THIS SHOULD NOT BE RELIED UPON
// We should attach .catch() listeners to all promises ASAP
process.removeAllListeners('unhandledRejection').on('unhandledRejection', function(err, p) {
p.catch(function(error) {
log(error, logType.critical);
});
});
global.handleUnexpectedRejection = function(error) {
log(error, logType.critical);
}
process.on('uncaughtException', function(err) {
//Uncaught Exception
if (err.code == "ECONNRESET") {
log("Uncaught Exception: ECONNRESET", logType.critical);
log(err.stack, logType.critical);
} else {
log("Uncaught Exception:", logType.critical);
log(err.stack, logType.critical);
}
});
var stdinInterface = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
global.parseTime = function(time) {
if (time.endsWith("m")) {
return parseInt(time.substr(0, time.length - 1)) * 60;
} else if (time.endsWith("h")) {
return parseInt(time.substr(0, time.length - 1)) * 60 * 60;
} else if (time.endsWith("d")) {
return parseInt(time.substr(0, time.length - 1)) * 60 * 60 * 24;
} else if (time.endsWith("w")) {
return parseInt(time.substr(0, time.length - 1)) * 60 * 60 * 24 * 7;
} else if (time.endsWith("s")) {
return parseInt(time.substr(0, time.length - 1));
} else {
return parseInt(time) * 60;
}
}
var commandHistory = [];
function processConsoleInput(line) {
commandHistory.unshift(line);
logBox.log(line);
const memberLine = function(member) {
var line = member.id + " " + member.user.tag;
if (member.nickname != null) {
line += " [" + member.nickname + "]";
}
if (member.user.bot) {
line += " \x1b[46m[BOT]";
}
return line;
};
var lLine = line.toLowerCase();
if (lLine == "help") {
var help = "AstralMod Console Commands:\n" +
"save Saves AstralMod configuration settings to disk. This happens every 30 seconds.\n" +
"loadunenc [filename] Loads an unencrypted settings.json file from disk.\n" +
"dumpsettings Prints the settings file contents, unencrypted, to the console\n" +
"plugins List loaded plugins\n" +
"load [plugin] Loads a plugin into AstralMod\n" +
"unload [plugin] Unloads a plugin from AstralMod\n" +
"reload [plugin] Unloads and then loads a plugin into AstralMod\n" +
"broadcast [message] Broadcasts a message to every server AstralMod is connected to\n" +
"vacuum Check the AstralMod Configuration File for errors\n" +
"reconnect Attempts to disconnect and reconnect to Discord\n" +
"guilds Lists guilds AstralMod knows about\n" +
"ginfo [guildid] Shows information about a guild\n" +
"ginfom [guildid] Shows members inside a guild\n" +
"ginfoc [guildid] Shows channels inside a guild\n" +
"ginfob [guildid] Shows bans of a guild\n" +
"cinfo [channelid] Finds a channel by its ID\n" +
"block [userid] Globally blocks a user from using AstralMod\n" +
"unblock [userid] Unblocks a user from AstralMod\n" +
"exit Exits AstralMod";
log(help, logType.info);
} else if (lLine == "exit") {
shutdown();
} else if (lLine == "loadunenc") {
log("Usage: loadunenc [filename]", logType.critical);
} else if (lLine.startsWith("loadunenc ")) {
var file = line.substr(10);
try {
var json = fs.readFileSync(file, "utf8");
var object = JSON.parse(json);
if (object != null) {
settings = object;
fs.unlink(file);
log("Settings loaded successfully, and the file has been deleted from disk. Please use the vacuum command now.", logType.good);
}
} catch (err) {
log("Couldn't load settings", logType.critical);
}
} else if (lLine == "dumpsettings") {
log(JSON.stringify(settings, null, 4), logType.info);
} else if (lLine == "plugins") {
var pluginsList = "Loaded plugins:";
for (plugin in plugins) {
pluginsList += "\n" + plugin;
}
log(pluginsList, logType.info);
} else if (lLine.startsWith("unload ")) {
unloadPlugin(line.substr(7));
log("Plugin " + line.substr(7) + " unloaded.", logType.good);
} else if (lLine == "unload") {
log("Usage: unload [filename]", logType.critical);
} else if (lLine.startsWith("load ")) {
if (loadPlugin(line.substr(5))) {
log("Plugin " + line.substr(5) + " loaded.", logType.good);
}
} else if (lLine == "load") {
log("Usage: load [filename]", logType.critical);
} else if (lLine.startsWith("reload ")) {
unloadPlugin(line.substr(7));
log("Plugin " + line.substr(7) + " unloaded.", logType.good);
if (loadPlugin(line.substr(7))) {
log("Plugin " + line.substr(7) + " loaded.", logType.good);
}
} else if (lLine == "reload") {
log("Usage: reload [filename]", logType.critical);
} else if (lLine == "save") {
saveSettings(true);
} else if (lLine == "reconnect") {
if (consts.keys.token != null) {
client.login(consts.keys.token).catch(function() {
log("Couldn't establish a connection to Discord.", logType.critical);
});
} else {
log("Couldn't find token", logType.critical);
}
} else if (lLine.startsWith("block ")) {
let blocked = line.substr(6);
if (settings.generalConfiguration.blockedUsers == undefined) {
settings.generalConfiguration.blockedUsers = []
}
settings.generalConfiguration.blockedUsers.push(blocked);
} else if (lLine.startsWith("unblock ")) {
let unblocked = line.substr(8);
if (settings.generalConfiguration.blockedUsers == undefined) {
settings.generalConfiguration.blockedUsers = [];
return;
}
settings.generalConfiguration.blockedUsers = settings.generalConfiguration.blockedUsers.filter(u => u != unblocked);
} else if (lLine == "blocked") {
if (settings.generalConfiguration.blockedUsers == undefined) {
settings.generalConfiguration.blockedUsers = [];
return;
}
log("List of blocked users:", logType.info);
for (let blocked of settings.generalConfiguration.blockedUsers) {
log(blocked, logType.info);
}
} else if (lLine.startsWith("broadcast ")) {
//Broadcast message to each server in either #general or the bot warnings general
var broadcast = line.substr(10);
log("Broadcasting message: " + broadcast, logType.info);
//Iterate over each server
for (key in settings.guilds) {
var guildSetting = settings.guilds[key];
var guild = client.guilds.get(key);
if (guildSetting != null) {
var channel = null;
if (guildSetting.botWarnings != null) {
if (guild != null) {
channel = guild.channels.get(guildSetting.botWarnings);
}
}
if (channel == null && guild != null && guild.channels.size > 0) {
//channel = guild.defaultChannel;
channel = guild.channels.array()[0];
}
if (channel != null) {
channel.send("SERVICE ANNOUNCEMENT: " + broadcast);
}
}
}
log("Broadcasting message complete", logType.good);
} else if (lLine == "broadcast") {
log("Usage: broadcast message", logType.critical);
} else if (lLine == "vacuum") {
vacuumSettings();
} else if (lLine.startsWith("cinfo ")) {
var channelId = line.substr(6);
var channel = client.channels.get(channelId);
if (channel == null) {
log("Unknown channel.", logType.info);
} else {
var info = "Information for channel " + channelId + ":\n" +
"Name: " + channel.name + "\n" +
"Guild: " + channel.guild.name + " [" + channel.guild.id + "]";
log(info, logType.info);
}
} else if (lLine == "cinfo") {
log("Usage: cinfo [channelid]", logType.critical);
} else if (lLine == "guilds") {
var response = "Guilds AstralMod is connected to:";
for ([id, guild] of client.guilds) {
response += "\n" + guild.id + " " + guild.name + "";
}
log(response, logType.info);
} else if (lLine.startsWith("ginfo ")) {
var guildLine = line.substr(6);
var guild = client.guilds.get(guildLine);
if (guild == null) {
log("Unknown guild.", logType.info);
} else {
var info = "Information for guild " + guildLine + ":\n" +
"Name: " + guild.name + "\n" +
"Owner: " + memberLine(guild.owner) + "\n" +
"Members: " + parseInt(guild.memberCount) + "\n" +
"Channels: " + parseInt(guild.channels.size);
log(info, logType.info);
}
} else if (lLine.startsWith("ginfom ")) {
var guildLine = line.substr(7);
var guild = client.guilds.get(guildLine);
if (guild == null) {
log("Unknown guild.", logType.info);
} else {
var info = "Information for guild " + guildLine + ":\n" +
"Members: " + parseInt(guild.memberCount);
for ([id, member] of guild.members) {
info += "\n" + memberLine(member);
}
log(info, logType.info);
}
} else if (lLine.startsWith("ginfoc ")) {
var guildLine = line.substr(7);
var guild = client.guilds.get(guildLine);
if (guild == null) {
log("Unknown guild.", logType.info);
} else {
var info = "Information for guild " + guildLine + ":\n" +
"Members: " + parseInt(guild.channels.size);
for ([id, channel] of guild.channels) {
info += "\n" + channel.id + " " + (channel.type == "text" ? "#" : " ") + channel.name;
}
log(info, logType.info);
}
} else if (lLine.startsWith("ginfob ")) {
var guildLine = line.substr(7);
var guild = client.guilds.get(guildLine);
if (guild == null) {
log("Unknown guild.", logType.info);
} else {
guild.fetchBans().then(function(bans) {
var info = "Information for guild " + guildLine + ":\n" +
"Bans: " + parseInt(bans.size);
for ([id, user] of bans) {
info += "\n" + user.id + " " + user.username + "#" + user.discriminator;
}
log(info, logType.info);
}).catch(function() {
log("Couldn't fetch bans for that guild.", logType.critical);
});
}
} else if (lLine.startsWith("send ")) {
var args = line.substr(5);
var split = args.indexOf(" ");
if (split == -1) {
log("Usage: send [channelid] [message]", logType.critical);
} else {
var message = args.substr(split + 1);
var channel = args.substr(0, split);
var dChannel = client.channels.get(channel);
if (dChannel == null) {
log("Couldn't find that channel.", logType.critical);
} else {
dChannel.send(message);
log("Sent.", logType.good);
}
}
} else if (lLine == "send") {
log("Usage: send [channelid] [message]", logType.critical);
} else if (lLine == "ginfo") {
log("Usage: ginfo [guildid]", logType.critical);
} else {
log("Unknown command. For help, type \"help\" into the console.", logType.critical);
}
}
textBox.on("submit", function() {
//Input received!
var line = textBox.getText().substr(2);
hideTextBox();
processConsoleInput(line);
});
textBox.key('backspace', function() {
var line = textBox.getText();
if (!line.startsWith("> ")) {
if (line == ">") {
line = "> ";
} else if (line.startsWith(" ")) {
line = "> " + line.substring(1);
} else {
line = "> " + line;
}
textBox.setValue(line);
}
});
textBox.key('tab', function() {
//Autocomplete!
var line = textBox.getText().substr(2, textBox.getText().length - 6);
textBox.setValue("> " + line);
var lLine = line.toLowerCase();
if (lLine.startsWith("ginfo ")) {
var guildLine = line.substr(6);
var guilds = [];
for ([id, guild] of client.guilds) {
var id = guild.id;
if (id.startsWith(guildLine)) {
guilds.push(guild.id);
}
}
if (guilds.length == 1) {
textBox.setValue("> ginfo " + guilds[0]);
} else if (guilds.length == 0) {
log("No results.", logType.info)
} else {
var acOutput = "";
for (guild of guilds) {
acOutput += guild + " ";
}
log(acOutput, logType.info);
}
} else if (lLine.startsWith("ginfom ")) {
var guildLine = line.substr(7);
var guilds = [];
for ([id, guild] of client.guilds) {
var id = guild.id;
if (id.startsWith(guildLine)) {
guilds.push(guild.id);
}
}
if (guilds.length == 1) {
textBox.setValue("> ginfom " + guilds[0]);
} else if (guilds.length == 0) {
log("No results.", logType.info)
} else {
var acOutput = "";
for (guild of guilds) {
acOutput += guild + " ";
}
log(acOutput, logType.info);
}
} else if (lLine.startsWith("ginfoc ")) {
var guildLine = line.substr(7);
var guilds = [];
for ([id, guild] of client.guilds) {
var id = guild.id;
if (id.startsWith(guildLine)) {
guilds.push(guild.id);
}
}
if (guilds.length == 1) {
textBox.setValue("> ginfoc " + guilds[0]);
} else if (guilds.length == 0) {
log("No results.", logType.info)
} else {
var acOutput = "";
for (guild of guilds) {
acOutput += guild + " ";
}
log(acOutput, logType.info);
}
} else if (lLine.startsWith("ginfob ")) {
var guildLine = line.substr(7);
var guilds = [];
for ([id, guild] of client.guilds) {
var id = guild.id;
if (id.startsWith(guildLine)) {
guilds.push(guild.id);
}
}
if (guilds.length == 1) {
textBox.setValue("> ginfob " + guilds[0]);
} else if (guilds.length == 0) {
log("No results.", logType.info)
} else {
var acOutput = "";
for (guild of guilds) {
acOutput += guild + " ";
}
log(acOutput, logType.info);
}
} else if (lLine.startsWith("send ")) {
var channelLine = line.substr(5);
if (channelLine.indexOf(" ") == -1) {
var channels = [];
for ([id, channel] of client.channels) {
var id = channel.id;
if (id.startsWith(channelLine)) {
channels.push(channel.id);
}
}
if (channels.length == 1) {
textBox.setValue("> send " + channels[0] + " ");
} else if (channels.length == 0) {
log("No results.", logType.info)
} else {
var acOutput = "";
for (channel of channels) {
acOutput += channel + " ";
}
log(acOutput, logType.info);
}
}
} else if (lLine.startsWith("cinfo ")) {
var channelLine = line.substr(6);
if (channelLine.indexOf(" ") == -1) {
var channels = [];
for ([id, channel] of client.channels) {
var id = channel.id;
if (id.startsWith(channelLine)) {
channels.push(channel.id);
}
}
if (channels.length == 1) {
textBox.setValue("> cinfo " + channels[0]);
} else if (channels.length == 0) {
log("No results.", logType.info)
} else {
var acOutput = "";
for (channel of channels) {
acOutput += channel + " ";
}
log(acOutput, logType.info);
}
}
} else {
log("Command autocompletion coming soon.", logType.info);
//TODO: Command autocompletion
}
});
log("Welcome to AstralMod!", logType.good);
global.getUserString = function(user) {
var u = user;
if (user.user != null) {
u = user.user;
}
return u.tag;
}
global.parseUser = function(query, guild = null) {
if (query.startsWith("<@!") && query.endsWith(">")) {
query = query.substr(3);
query = query.slice(0, -1);
} else if (query.startsWith("<@") && query.endsWith(">")) {
query = query.substr(2);
query = query.slice(0, -1);
}
var searchResults = [];
for (let [snowflake, user] of client.users) {
if (user.username.toLowerCase() == query.toLowerCase()) {
searchResults.unshift(user);
} else if (user.username.toLowerCase().indexOf(query.toLowerCase()) != -1) {
searchResults.push(user);
} else if ((user.username.toLowerCase() + "#" + user.discriminator).indexOf(query.toLowerCase()) != -1) {
searchResults.push(user);
} else if (user.id == query) {
searchResults.unshift(user);
}
}
if (guild != null) {
var guildSpecificResults = [];
for (let [snowflake, member] of guild.members) {
if (member.nickname != null) {
if (member.nickname.toLowerCase() == query.toLowerCase()) {
guildSpecificResults.unshift(member.user);
} else if (member.nickname.toLowerCase().indexOf(query.toLowerCase()) != -1) {
guildSpecificResults.push(member.user);
}
}
}
var pop = guildSpecificResults.pop();
while (pop != undefined) {
searchResults.unshift(pop);
pop = guildSpecificResults.pop();
}
}
return searchResults;
}
function setGame() {
client.user.setActivity(getRandom("with ban buttons",
"Annoying Victor",
prefix() + "help",
"Version " + amVersion,
"Google Pay",
"theShell",
"Monopoly",
"Final Fantastic Card",
"Ski jacket shopping"),
{
type: "PLAYING"
}
);
}
function isMod(member) {
if (member.id == global.botOwner.id)
return true;
if (tempMods[member.guild.id] != null && tempMods[member.guild.id].includes(member.id)) {
return true;
}
var modRoles = settings.guilds[member.guild.id].modRoles;
if (modRoles == null) {
if (member.permissions.has(Discord.Permissions.FLAGS.BAN_MEMBERS, true)) {
return true;
}
} else {
for (role of modRoles) {
if (member.roles.has(role)) {
return true;
}
}
}
return false;
}
global.uinfo = function(user, channel, locale, offset, h24 = true, guild = null, compact = false) {
let $ = _[locale];
sendPreloader($("UINFO_RETRIEVING"), channel).then(function(messageToEdit) {
var member = null;
if (guild != null) {
for ([id, gMember] of guild.members) {
if (gMember.user.id == user.id) {
member = gMember;
break;
}
}
if (member == null) {
member = {
displayName: user.username,
tag: user.tag,
noGuild: true,
noGuildMessage: $("UINFO_NOT_PART_OF_SERVER"),
user: user
}
}
} else {
member = {
displayName: user.username,
tag: user.tag,
noGuild: true,
noGuildMessage: $("UINFO_NOT_ALLOWED_SERVER_SPECIFIC"),
user: user
}
}
var embed = new Discord.RichEmbed("uinfo");
embed.setAuthor(member.displayName, user.displayAvatarURL);
embed.setAuthor(getUserString(member), user.displayAvatarURL);
embed.setColor(consts.colors.info);
embed.setFooter($("UINFO_USER_ID", {id:user.id}));
if (compact) {
var msg = $("UINFO_DISCRIMINATOR", {discriminator:user.discriminator}) + "\n" +
$("UINFO_CREATEDAT", {createdat:{date: member.user.createdAt, h24: h24, offset: offset}}) + "\n";
if (member.noGuild != true) {
if (member.joinedAt.getTime() == 0) {
msg += $("UINFO_JOINEDAT", {joinedat:$("UINFO_INVALID_JOIN")});
} else {
msg += $("UINFO_JOINEDAT", {joinedat:{date: member.joinedAt, h24: h24, offset: offset}});
}
}
embed.setDescription(msg);
} else {
if (member.noGuild != true) {
embed.setDescription($("UINFO_USER_INFORMATION"));
} else {
embed.setDescription(member.noGuildMessage);
}
{
var msg = $("UINFO_CREATEDAT", {createdat:{date:member.user.createdAt, h24:h24, offset: offset}}) + "\n";
if (member.noGuild != true) {
if (member.joinedAt.getTime() == 0) {
msg += $("UINFO_JOINEDAT", {joinedat:$("UINFO_INVALID_JOIN")});
} else {
msg += $("UINFO_JOINEDAT", {joinedat:{date:member.joinedAt, h24:h24, offset: offset}});
}
}
embed.addField($("UINFO_TIMESTAMPS"), msg);
}
var msg;
if (member.noGuild) {
msg = $("UINFO_USERNAME", {username:user.username});
embed.addField($("UINFO_NAMES"), msg);
} else {
msg = $("UINFO_DISPLAYNAME", {displayname:member.displayName}) + "\n";
msg += $("UINFO_USERNAME", {username:user.username}) + "\n";
msg += $("UINFO_NICKNAME",{nickname: (member.nickname == null ? $("UINFO_NONICKNAME") : member.nickname)});
embed.addField($("UINFO_NAMES"), msg);
}
{
var msg = "";
if (user.bot) {
msg += "- " + $("UINFO_BOT_ACCOUNT_WARNING") + "\n";
}
if (banCounts[user.id] != 0 && banCounts[user.id] != null) {
msg += "- " + $("UINFO_BANNED_FROM", {count:parseInt(banCounts[user.id])});
}
if (msg != "") {
embed.addField($("UINFO_ALERTS"), msg);
}
}
}
messageToEdit.edit(embed);
}).catch(handleUnexpectedRejection);
}
function processModCommand(message, command) {
let $ = _[settings.users[message.author.id].locale];
var text = message.content;
var lText = text.toLowerCase();
let options = {
locale: settings.users[message.author.id].locale,
imperial: settings.users[message.author.id].units === "imperial",
h24: settings.users[message.author.id].timeunit !== "12h",
offset: settings.users[message.author.id].timezone
};
//Special cases
if (lText == prefix(message.guild.id) + "config") {
//Make sure person isn't configuring any other guild
for (key in settings.guilds) {
var guildSetting = settings.guilds[key];
if (guildSetting != null) {
if (guildSetting.configuringStage != 0) {
if (guildSetting.configuringUser == message.author.id) {
message.reply($("CONFIG_ALREADY_CONFIGURATING", {guild: client.guilds.get(key).name}));
return true;
}
}
}
}
//Clear all user configuring for this user
for (key in settings.guilds) {
var guildSetting = settings.guilds[key];
if (guildSetting != null) {
if (guildSetting.configuringUser == message.author.id) {
settings.guilds[key].configuringUser = null;
}
}
}
if (settings.guilds[message.guild.id].requiresConfig) {
// This branch is dead; no strings here need translation
if (message.author.id == global.botOwner.id || message.author.id == message.guild.owner.user.id) {
settings.guilds[message.guild.id].configuringUser = message.author.id;
settings.guilds[message.guild.id].configuringStage = 0;
message.author.send("Welcome to AstralMod! To start, let's get the roles of mods on the server. Enter the roles of mods on this server, separated by a space.");
var roles = "```";
for (let [, role] of message.guild.roles) {
roles += role.id + " = " + role.name + "\n";
}
roles += "```";
message.author.send(roles);
message.reply(":arrow_left: Continue in DMs.");
return true;
} else {
message.reply("You're not " + message.guild.owner.displayName);
return true;
}
} else {
//Configuration menu
//Make sure person has necessary permissions
if (message.author.id == global.botOwner.id || message.author.id == message.guild.owner.user.id || message.member.hasPermission("ADMINISTRATOR")) {
settings.guilds[message.guild.id].configuringUser = message.author.id;
settings.guilds[message.guild.id].configuringStage = 0;
message.author.send($("CONFIG_INTRO"), getSingleConfigureWelcomeText(message.guild, message.author));
message.reply($("CONFIG_CONTINUE_IN_DMS"), {emoji: ":arrow_left:"});
}
}
} else if (lText == prefix(message.guild.id) + "poweroff") {
if (message.author.id == global.botOwner.id) {
message.reply("AstralMod is now exiting.").then(function () {
shutdown();
}).then(function() {
shudtdown();
});
}
}
if (isMod(message.member)) {
if (command.startsWith("oknick")) {
let userId = command.substr(7);
acceptNicknameChange(message.guild.id, userId, message.channel.id, options);
return true;
}
}
return false;
}
function requestNickname(member, nickname, guild, options) {
if (nickname.length > 32) {
return "length";
}
if (settings.guilds[guild.id].pendingNicks == null) {
settings.guilds[guild.id].pendingNicks = {};
}
let pendingNicks = settings.guilds[guild.id].pendingNicks; //save us some typing
if (pendingNicks.cooldowns == null) {
pendingNicks.cooldowns = {};
}
let botwarningsChannel = client.channels.get(settings.guilds[guild.id].botWarnings);
if (botwarningsChannel == null) {
return "configuration";
}
if (pendingNicks.cooldowns[member.user.id] == null || moment.utc().isSameOrAfter(moment(pendingNicks.cooldowns[member.user.id]).utc().add(1, 'd'))) {
pendingNicks.cooldowns[member.user.id] = moment.utc().toDate();
if (nickChanges[guild.id] == null) {
nickChanges[guild.id] = {};
}
nickChanges[guild.id][member.user.id] = nickname;
let botwarningsChannelMessage;
if (nickname == "") {
botwarningsChannelMessage = ":arrows_counterclockwise: <@" + member.user.id + "> :arrow_right: `[clear]`. `" + prefix(member.guild.id) + "oknick " + member.user.id + "`";
} else {
botwarningsChannelMessage = ":arrows_counterclockwise: <@" + member.user.id + "> :arrow_right: `" + nickname + "`. `" + prefix(member.guild.id) + "oknick " + member.user.id + "`";
}
botwarningsChannel.send(botwarningsChannelMessage).then(function(message) {
message.react("✅").then(function() {
let acceptor;
message.awaitReactions(function(reaction) {
if (reaction.count <= 1) return false;
for (let user of reaction.users) {
if (isMod(message.guild.member(user[1]))) {
return true;
}
}
return false;
}, {
max: 1
}).then(function() {
//Accept the nickname
acceptNicknameChange(message.guild.id, member.user.id, message.channel.id, options);
});
});
}).catch(handleUnexpectedRejection);
settings.guilds[guild.id].pendingNicks = pendingNicks;
return "ok";
} else {
settings.guilds[guild.id].pendingNicks = pendingNicks;
return moment(pendingNicks.cooldowns[member.user.id]).utc().add(1, 'd');
}
}
function acceptNicknameChange(guildId, userId, channelId, options) {
let $ = _[options.locale];
let guild = client.guilds.get(guildId);
if (nickChanges[guildId] != null) {
if (nickChanges[guildId][userId] != null) {
client.fetchUser(userId).then(function(user) {
return guild.fetchMember(user);
}).then(function(member) {
return member.setNickname(nickChanges[guildId][userId]);
}).then(function() {
nickChanges[guildId][userId] = null;
guild.channels.get(channelId).send($("OKNICK_ACCEPTED", {emoji: ":white_check_mark:"}));
}).catch(function() {
guild.channels.get(channelId).send($("OKNICK_THAT_DIDNT_WORK", {emoji: ":no_entry_sign:"}));
});
} else {
guild.channels.get(channelId).send($("OKNICK_THAT_DIDNT_WORK", {emoji: ":no_entry_sign:"}));
}
}
}
function getNickStatus(member, nickname, guild) {
if (nickname.length > 32) {
return "length";
}
let botwarningsChannel = client.channels.get(settings.guilds[guild.id].botWarnings);
if (botwarningsChannel == null) {
return "configuration";
}
let pendingNicks = settings.guilds[guild.id].pendingNicks; //save us some typing
if (pendingNicks == null || pendingNicks.cooldowns[member.user.id] == null || moment.utc().isSameOrAfter(moment(pendingNicks.cooldowns[member.user.id]).utc().add(1, 'd'))) {
return "ok";
}
return moment.duration(moment.utc().add(1, "day").diff(pendingNicks.cooldowns[member.user.id]));
}
function processAmCommand(message, options, command) {
var text = message.content;
var command;
let $ = _[options.locale];
if (command == "ping") {
let pingDate = Date.now();
message.channel.send($("PING_PINGING", {emoji: getEmoji("signal0"), interpolation: { escapeValue: false }})).then(function(message) {
let time = Date.now() - pingDate;
/* Times:
0 - 100ms: signal5
100 - 200ms: signal4
200 - 300ms: signal3
300 - 500ms: signal2
500 - 1000ms: signal1
1000ms+: signal0
*/
if (time == 420) {
message.edit($("PING_DONE_420", {emoji: getEmoji("signal2"), interpolation: { escapeValue: false }}));
} else {
let e;
if (time < 100) {
e = getEmoji("signal5");
} else if (time <= 200) {
e = getEmoji("signal4");
} else if (time <= 300) {
e = getEmoji("signal3");
} else if (time <= 500) {
e = getEmoji("signal2");
} else if (time <= 1000) {
e = getEmoji("signal1");
} else {
e = getEmoji("signal0");
}
message.edit($("PING_DONE", {emoji: e, time: time.toString(), interpolation: {escapeValue: false}}));
}
}).catch(function(error) {
log("Uncaught Exception:", logType.critical);
log(error.stack, logType.critical);
});
return true;
} else if (command == "nick") {
if (settings.guilds[message.guild.id].nickModeration) {
let nickResult = getNickStatus(message.member, "", message.guild);
if (moment.isDuration(nickResult)) {
message.reply($("NICK_WAIT", {time: {duration: nickResult}}));
} else if (nickResult == "length") {
message.reply($("NICK_TOO_LONG"));
} else if (nickResult == "configuration") {
message.reply($("NICK_SERVER_IMPROPER_CONFIG", {prefix: prefix(message.guild.id)}));
} else {
awaitUserConfirmation({
title: $("NICK_RESET_REQUEST_TITLE"),
msg: $("NICK_RESET_REQUEST_MESSAGE"),
msgOnSuccess: $("NICK_RESET_REQUEST_SUCCESS"),
msgOnFail: $("NICK_REQUEST_CANCEL"),
channel: message.channel,
author: message.author,
locale: options.locale
}).then(() => {
requestNickname(message.member, text.substr(8), message.guild, options);
}).catch(() => {
//Don't do anything
});
}
} else {
message.reply($("NICK_NOT_ACCEPTED"));
}
return true;
} else if (command.startsWith("nick ")) {
if (settings.guilds[message.guild.id].nickModeration) {
let nickResult = getNickStatus(message.member, text.substr(8), message.guild);
if (moment.isDuration(nickResult)) {
message.reply($("NICK_WAIT", {time: {duration: nickResult}}));
} else if (nickResult == "length") {
message.reply($("NICK_TOO_LONG"));
} else if (nickResult == "configuration") {
message.reply($("NICK_SERVER_IMPROPER_CONFIG", {prefix: prefix(message.guild.id)}));
} else {
awaitUserConfirmation({
title: $("NICK_CHANGE_REQUEST_TITLE"),
msg: $("NICK_CHANGE_REQUEST_MESSAGE"),
msgOnSuccess: $("NICK_CHANGE_REQUEST_SUCCESS"),
msgOnFail: $("NICK_REQUEST_CANCEL"),
channel: message.channel,
author: message.author,
extraFields: [
[$("NICK_NICKNAME"), text.substr(8)]
],
locale: options.locale
}).then(function() {
requestNickname(message.member, text.substr(8), message.guild, options);
}).catch(function() {
//Don't do anything
});
}
} else {
message.reply($("NICK_NOT_ACCEPTED"));
}
return true;
} else if (command == "version") {
message.channel.send($("VERSION", {version: amVersion}));
return true;
} else if (command == "about") {
let embed = new Discord.RichEmbed();
embed.setColor(consts.colors.done);
embed.setAuthor($("ABOUT_TITLE", {verion: amVersion}), client.user.avatarURL);
embed.setDescription($("ABOUT_ABOUT"));
embed.addField($("ABOUT_FILE_BUG"), $("ABOUT_FILE_BUG_CONTENT", {link: "(https://github.com/vicr123/AstralMod/issues)"}));
embed.addField($("ABOUT_SOURCE"), $("ABOUT_SOURCE_CONTENT", {link: "(https://github.com/vicr123/AstralMod/issues)"}));
embed.addField($("ABOUT_CONTRIBUTORS"), $("ABOUT_CONTRIBUTORS_CONTENT", {contributors: "\n- Blake#0007\n- reflectronic#5190"}));
embed.setFooter($("ABOUT_THANKS", {version: amVersion}));
message.channel.send(embed);
return true;
} else if (command == "setlocale") {
let embed = new Discord.RichEmbed();
embed.setColor(consts.colors.done);
embed.setAuthor($("SETLOC_TITLE"));
let thisLocale = $("THIS_LOCALE");
if (options.locale == "en") thisLocale = "English";
embed.addField($("SETLOC_YOUR_LOCALE"), "`" + options.locale + "` - " + thisLocale);
let availableLocales = "";
for (let locale of availableTranslations) {
let thisLocale = _[locale]("THIS_LOCALE");
if (thisLocale == _.en("THIS_LOCALE")) thisLocale = "";
if (locale == "en") thisLocale = "English";
availableLocales += "`" + locale + "` - " + thisLocale + "\n";
}
embed.addField($("SETLOC_AVAILABLE_LOCALES"), availableLocales);
embed.setFooter($("SETLOC_DISCLAIMER"));
message.channel.send(embed);
} else if (command.startsWith("setlocale ")) {
let locale = command.substr(10);
let setLocale = function(locale) {
settings.users[message.author.id].locale = locale;
let thisLocale = _[locale]("THIS_LOCALE");
if (locale == "en") thisLocale = "English";
let embed = new Discord.RichEmbed();
embed.setColor(consts.colors.done);
embed.setAuthor(_[locale]("SETLOC_TITLE"));
embed.setDescription(_[locale]("SETLOC_LANGUAGE", {locale: thisLocale}));
embed.setFooter(_[locale]("SETLOC_DISCLAIMER"));
message.channel.send(embed);
}
if (availableTranslations.getTranslation(locale) != undefined) {
setLocale(availableTranslations.getTranslation(locale));
return true;
}
//Locale unavailable
locale = settings.users[message.author.id].locale;
if (locale == null) locale = "en";
var embed = new Discord.RichEmbed();
embed.setColor(consts.colors.fail);
embed.setAuthor($("SETLOC_TITLE"));
embed.setDescription($("SETLOC_UNAVAILABLE"))
let availableLocales = "";
for (let locale of availableTranslations) {
let thisLocale = _[locale]("THIS_LOCALE");
if (thisLocale == _.en("THIS_LOCALE")) thisLocale = "";
if (locale == "en") thisLocale = "English";
availableLocales += "`" + locale + "` - " + thisLocale + "\n";
}
embed.addField($("SETLOC_AVAILABLE_LOCALES"), availableLocales);
embed.setFooter($("SETLOC_DISCLAIMER"));
message.channel.send(embed);
return true;
} else if (command == "help") { //General help
var embed = new Discord.RichEmbed();
embed.setColor(consts.colors.done);
embed.setAuthor($("HELP_CONTENTS"));
embed.setDescription($("HELP_CONTENTS_INTRODUCTION", {prefix: prefix(message.guild.id)}));
embed.addField($("HELP_CORE_COMMANDS"), "**config**\n**shoo**\n**oknick**\nping\nnick\nsetlocale\nsudo\nversion\nabout\nhelp", true);
for (key in plugins) {
var plugin = plugins[key];
if (plugin.availableCommands != null) {
var commandsList = "";
if (plugin.availableCommands.general != null) {
if (plugin.availableCommands.general.modCommands != null) {
for (command of plugin.availableCommands.general.modCommands) {
commandsList += "**" + command + "**\n";
}
}
if (plugin.availableCommands.general.commands != null) {
for (command of plugin.availableCommands.general.commands) {
commandsList += command + "\n";
}
}
}
if (plugin.availableCommands[message.guild.id] != null) {
if (plugin.availableCommands[message.guild.id].modCommands != null) {
for (command of plugin.availableCommands[message.guild.id].modCommands) {
commandsList += "**" + command + "**\n";
}
}
if (plugin.availableCommands[message.guild.id].commands != null) {
for (command of plugin.availableCommands[message.guild.id].commands) {
commandsList += command + "\n";
}
}
}
if (commandsList != "") {
if (plugin.translatableName == null) {
embed.addField(plugin.name, commandsList, true);
} else {
embed.addField(_.help[options.locale](plugin.translatableName), commandsList, true);
}
}
}
}
embed.setFooter($("HELP_FOOTER", {amVersion: amVersion}));
message.channel.send("", { embed: embed });
return true;
} else if (command.startsWith("sudo")) {
if (isMod(message.member)) {
message.reply($("SUDO_ALREADY_SUDO"));
return;
}
let embed = new Discord.RichEmbed;
embed.setTitle($("SUDO_TITLE", {emoji: ":shield:"}));
embed.setDescription($("SUDO_USER", {user: message.author.tag}) + "\n" +
$("SUDO_ROLE", {role: message.member.highestRole.name}) + "\n" +
$("SUDO_SERVER", {server: message.guild.name}));
embed.setFooter($("SUDO_FOOTER", {emoji1: "✅", emoji2: "🚫", time: "5"}));
embed.setColor(consts.colors.info);
message.channel.send(embed).then(m => {
m.react("✅");
m.react("🚫");
let okay = false;
if (global.tempMods[message.guild.id] == null) global.tempMods[message.guild.id] = [];
let collector = m.createReactionCollector(function(reaction) {
if (reaction.count <= 1) return false;
if (reaction.emoji.name == "✅" || reaction.emoji.name == "🚫") {
for (let user of reaction.users) {
if (isMod(message.guild.members.get(user[0])) && user[1].id != client.user.id || (reaction.emoji.name == "🚫" && user[1].id == message.author.id)) {
return true;
}
}
}
return false;
}, {time: 300000});
collector.on('collect', r => {
if (r.emoji.name == "✅") {
global.tempMods[message.guild.id].push(message.author.id);
setTimeout(() => global.tempMods[message.guild.id].splice(global.tempMods[message.guild.id].indexOf(message.author.id), 1), 300000)
embed.setDescription($("SUDO_FULFILLED_DESCRIPTION"))
embed.setFooter($("AWAITUSERCONFIRMATION_FULFILLED"));
embed.setColor(consts.colors.done)
m.edit(embed);
m.clearReactions();
okay = true;
collector.stop();
} else if (r.emoji.name == "🚫") {
embed.setFooter($("AWAITUSERCONFIRMATION_CANCELLED"));
embed.setDescription($("SUDO_CANCELLED_DESCRIPTION"))
embed.setColor(consts.colors.fail)
m.edit(embed);
m.clearReactions();
okay = true;
collector.stop();
}
});
collector.on('end', () => {
if (!okay) {
embed.setFooter($("AWAITUSERCONFIRMATION_CANCELLED"));
embed.setDescription($("SUDO_TIMED_OUT"))
embed.setColor(consts.colors.fail)
m.edit(embed);
m.clearReactions();
}
});
})
} else if (command.startsWith("help ")) { //Contextual help
//Get help for specific command
let h$ = _.help[options.locale];
var embed = new Discord.RichEmbed();
embed.setAuthor($("HELP_CONTENTS"));
var helpCmd = command.substr(5);
var help = {};
switch (helpCmd) {
case "config":
help.title = prefix(message.guild.id) + "config";
help.helpText = h$("CONFIG_HELPTEXT");
break;
case "shoo":
help.title = prefix(message.guild.id) + "shoo";
help.helpText = h$("SHOO_HELPTEXT");
break;
case "oknick":
help.title = prefix(message.guild.id) + "oknick";
help.helpText = h$("OKNICK_HELPTEXT");
break;
case "ping":
help.title = prefix(message.guild.id) + "ping";
help.helpText = h$("PING_HELPTEXT");
break;
case "version":
help.title = prefix(message.guild.id) + "version";
help.helpText = h$("VERSION_HELPTEXT");
break;
case "nick":
help.title = prefix(message.guild.id) + "nick";
help.usageText = prefix(message.guild.id) + "nick nickname";
help.helpText = h$("NICK_HELPTEXT");
help.param1 = h$("NICK_PARAM1");
break;
case "setlocale":
help.title = prefix(message.guild.id) + "setlocale";
help.usageText = prefix(message.guild.id) + "setlocale [locale]";
help.helpText = h$("SETLOCALE_HELPTEXT");
break;
case "help":
help.title = prefix(message.guild.id) + "help";
help.usageText = prefix(message.guild.id) + "help [command]";
help.helpText = h$("HELP_HELPTEXT");
help.param1 = h$("HELP_PARAM1");
break;
case "about":
help.title = prefix(message.guild.id) + "about";
help.usageText = prefix(message.guild.id) + "about";
help.helpText = h$("ABOUT_HELPTEXT");
break;
case "sudo":
help.title = prefix(message.guild.id) + "sudo";
help.usageText = prefix(message.guild.id) + "sudo";
help.helpText = h$("SUDO_HELPTEXT");
break;
default:
//Look thorough plugins for help
for (key in plugins) {
var plugin = plugins[key];
if (plugin.acquireHelp != null) {
if (plugin.availableCommands != null) {
if (plugin.availableCommands.general != null) {
if (plugin.availableCommands.general.hiddenCommands != null) {
if (plugin.availableCommands.general.hiddenCommands.indexOf(helpCmd) != -1) {
help = plugin.acquireHelp(helpCmd, message, h$);
break;
}
}
if (plugin.availableCommands.general.modCommands != null) {
if (plugin.availableCommands.general.modCommands.indexOf(helpCmd) != -1) {
help = plugin.acquireHelp(helpCmd, message, h$);
break;
}
}
if (plugin.availableCommands.general.commands != null) {
if (plugin.availableCommands.general.commands.indexOf(helpCmd) != -1) {
help = plugin.acquireHelp(helpCmd, message, h$);
break;
}
}
}
if (plugin.availableCommands[message.guild.id] != null) {
if (plugin.availableCommands[message.guild.id].modCommands != null) {
if (plugin.availableCommands[message.guild.id].modCommands.indexOf(helpCmd) != -1) {
help = plugin.acquireHelp(helpCmd, message, h$);
break;
}
}
if (plugin.availableCommands[message.guild.id].commands != null) {
if (plugin.availableCommands[message.guild.id].commands.indexOf(helpCmd) != -1) {
help = plugin.acquireHelp(helpCmd, message, h$);
break;
}
}
}
}
}
}
}
if (help.helpText == null) {
embed.setColor(consts.colors.fail);
embed.setDescription($("HELP_UNAVAILABLE"));
} else {
embed.setColor(consts.colors.done);
if (help.title == null) {
embed.setDescription($("HELP_COMMAND_TITLE"));
} else {
embed.setDescription($("HELP_COMMAND_FOR", {title: help.title}));
}
if (help.usageText != null) {
embed.addField($("HELP_COMMAND_USAGE"), help.usageText);
}
embed.addField($("HELP_COMMAND_DESCRIPTION"), help.helpText);
if (help.options != null) {
var options = "```";
for (value of help.options) {
options += value + "\n";
}
options += "```";
embed.addField($("HELP_COMMAND_OPTIONS"), options);
}
if (help.availableOptions != null) {
embed.addField($("HELP_COMMAND_AVAILABLE_OPTIONS"), help.availableOptions);
}
if (help.param1 != null) {
embed.addField($("HELP_COMMAND_PARAM", {param: "1"}), help.param1);
}
if (help.param2 != null) {
embed.addField($("HELP_COMMAND_PARAM", {param: "2"}), help.param2);
}
if (help.param3 != null) {
embed.addField($("HELP_COMMAND_PARAM", {param: "3"}), help.param3);
}
if (help.remarks != null) {
embed.addField($("HELP_COMMAND_REMARKS"), help.remarks);
}
}
embed.setFooter("AstralMod " + amVersion);
message.channel.send("", { embed: embed });
return true;
} else if (command.startsWith("throw ")) {
var msg = command.substr(6);
throw new Error(msg);
return true;
} else if (command == "shoo") {
if (message.author.id == global.botOwner.id | message.member.hasPermission(Discord.Permissions.FLAGS.KICK_MEMBERS, false, true, true)) {
awaitUserConfirmation({
title: $("SHOO_TITLE"),
msg: $("SHOO_MESSAGE"),
msgOnSuccess: $("SHOO_SUCCESS", {emoji: ":arrow_left:"}),
msgOnFail: $("SHOO_CANCEL"),
channel: message.channel,
author: message.author,
time: 10,
locale: options.locale
}).then(() => {
message.guild.leave().catch(function() {
message.reply($("SHOO_FAILURE"));
});
saveSettings();
}).catch(err => {
//Do nothing
});
} else {
message.reply($("SHOO_NO_PERMS"));
}
return true;
}
return false;
}
function getChannels(guild) {
let str = "```\n";
for (let channel of guild.channels.array().sort((a, b) => a.name.localeCompare(b.name))) {
if (channel.type == "text" && channel.permissionsFor(guild.me).has("SEND_MESSAGES")) {
str += `${channel.id} — #${channel.name}\n`
}
}
str += "```"
return str;
}
function getSingleConfigureWelcomeText(guild, author) {
var guildSetting = settings.guilds[guild.id];
let $ = _[settings.users[author.id].locale];
let embed = new Discord.RichEmbed();
if (guildSetting.modRoles == null) {
embed.addField($("CONFIG_STAFF_ROLES_TITLE", {number: 1}), $("CONFIG_STAFF_ROLES_DISCORD_PERMISSIONS"), true);
} else {
embed.addField($("CONFIG_STAFF_ROLES_TITLE", {number: 1}), $("CONFIG_STAFF_ROLES_COUNT", {count: guildSetting.modRoles.length}), true);
}
if (guild.channels.get(guildSetting.memberAlerts) == null) {
embed.addField($("CONFIG_MEMBER_ALERTS_TITLE", {number: 2}), $("CONFIG_DISABLED"), true);
} else {
embed.addField($("CONFIG_MEMBER_ALERTS_TITLE", {number: 2}), `<#${guild.channels.get(guildSetting.memberAlerts).id}>`, true);
}
if (guild.channels.get(guildSetting.chatLogs) == null) {
embed.addField($("CONFIG_CHAT_LOGS_TITLE", {number: 3}), $("CONFIG_DISABLED"), true);
} else {
embed.addField($("CONFIG_CHAT_LOGS_TITLE", {number: 3}), `<#${guild.channels.get(guildSetting.chatLogs).id}>`, true);
}
if (guild.channels.get(guildSetting.botWarnings) == null) {
embed.addField($("CONFIG_BOT_WARNINGS_TITLE", {number: 4}), $("CONFIG_DISABLED"), true);
} else {
embed.addField($("CONFIG_CHAT_LOGS_TITLE", {number: 4}), `<#${guild.channels.get(guildSetting.botWarnings).id}>`, true);
}
if (guild.channels.get(guildSetting.suggestions) == null) {
embed.addField($("CONFIG_SUGGESTIONS_TITLE", {number: 5}), $("CONFIG_DISABLED"), true);
} else {
embed.addField($("CONFIG_SUGGESTIONS_TITLE", {number: 5}), `<#${guild.channels.get(guildSetting.suggestions).id}>`, true);
}
if (guildSetting.locale == null) {
guildSetting.locale = "en"
}
let thisLocale = _[guildSetting.locale]("THIS_LOCALE");
if (thisLocale == _.en("THIS_LOCALE")) thisLocale = "";
if (guildSetting.locale == "en") thisLocale = "English";
embed.addField($("CONFIG_LOCALE_TITLE", {number: 6}), `${thisLocale} (${guildSetting.locale})`, true);
embed.addField($("CONFIG_SERVER_PREFIX_TITLE", {number: 7}), guildSetting.serverPrefix === undefined ? $("CONFIG_SERVER_PREFIX_DEFAULT", {prefix: prefix()}) : guildSetting.serverPrefix, true);
if (guildSetting.nickModeration == null || guildSetting.nickModeration == false) {
embed.addField($("CONFIG_NICK_MODERATION_TITLE", {number: "A"}), $("CONFIG_DISABLED"), true);
} else {
embed.addField($("CONFIG_NICK_MODERATION_TITLE", {number: "A"}), $("CONFIG_ENABLED"), true);
}
if (guildSetting.echoOffensive == null || guildSetting.echoOffensive == false) {
embed.addField($("CONFIG_FILTERING_TITLE", {number: "B"}), $("CONFIG_DISABLED"), true);
} else {
embed.addField($("CONFIG_FILTERING_TITLE", {number: "B"}), $("CONFIG_ENABLED"), true);
}
if (guildSetting.pinToPin == null || guildSetting.pinToPin == false) {
embed.addField($("CONFIG_PIN_TO_PIN_TITLE", {number: "C"}), $("CONFIG_DISABLED"), true);
} else {
embed.addField($("CONFIG_PIN_TO_PIN_TITLE", {number: "C"}), $("CONFIG_ENABLED"), true);
}
embed.setFooter($("CONFIG_FOOTER"));
embed.setColor(consts.colors.info)
return embed;
}
function processSingleConfigure(message, guild) {
let $ = _[settings.users[message.author.id].locale]
var text = message.content.toLowerCase();
var guildSetting = settings.guilds[guild.id];
switch (guildSetting.configuringStage) {
case -10: { //Reset AstralMod
if (message.content == "Reset AstralMod") { //Purge all configuration for this server
log("Purging all configuration for " + guild.id);
guildSetting = {
requiresConfig: false
};
log("Configuration for " + guild.id + " purged.", logType.good);
message.author.send($("CONFIG_CONFIG_PURGED", {prefix: prefix(message.guild.id)}));
} else { //Cancel
message.author.send($("CONFIG_CANCEL_CONFIGURATION"));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
}
break;
}
case 0: { //Main Menu
switch (text) {
case "1": //Staff Roles
settings.guilds[guild.id].configuringUser = message.author.id;
settings.guilds[guild.id].configuringStage = 0;
message.author.send($("CONFIG_STAFF_SETUP"));
var roles = "```";
for (let role of guild.roles.array().sort((a, b) => a.name.localeCompare(b.name))) {
roles += role.id + " — " + role.name + "\n";
}
roles += "```";
message.author.send(roles);
guildSetting.configuringStage = 10;
break;
case "2": //Member Alerts
message.author.send($("CONFIG_MEMBER_ALERT_SETUP"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 20;
break;
case "3": //Chat Logs
message.author.send($("CONFIG_CHAT_LOGS_SETUP"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 30;
break;
case "4": //Bot warnings
message.author.send($("CONFIG_BOT_WARNINGS_SETUP"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 40;
break;
case "5": //Suggestions
message.author.send($("CONFIG_SUGGESTIONS_SETUP"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 50;
break;
case "6": //Locale
message.author.send($("CONIFG_LOCALE_SETUP"));
let locales = "";
for (let locale of availableTranslations) {
let thisLocale = _[locale]("THIS_LOCALE");
if (thisLocale == _.en("THIS_LOCALE")) thisLocale = "";
if (locale == "en") thisLocale = "English";
locales += "`" + locale + "` - " + thisLocale + "\n";
}
message.author.send(locales);
guildSetting.configuringStage = 60;
break;
case "7": //Server prefix
message.author.send($("CONFIG_SERVER_PREFIX_SETUP"));
guildSetting.configuringStage = 70;
break;
case "0": //Exit
message.author.send($("CONFIG_CONFIGURATION_COMPLETE"));
guildSetting.configuringUser = null;
break;
case "a": //Nick Moderation
if (guildSetting.nickModeration) {
guildSetting.nickModeration = false;
} else {
guildSetting.nickModeration = true;
}
message.author.send($("CONFIG_NICK_MODERATION_TOGGLED"));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
break;
case "b": //Nick Moderation
if (guildSetting.echoOffensive) {
guildSetting.echoOffensive = false;
message.author.send($("CONFIG_FILTERING_OFF"));
} else {
guildSetting.echoOffensive = true;
message.author.send($("CONFIG_FILTERING_ON"));
}
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
break;
case "c": //Pin to pin
guildSetting.pinToPin = !guildSetting.pinToPin;
message.author.send($("CONFIG_PINTOPIN_TOGGLED", {emoji: consts.config.pinToPinEmoji}));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
break;
case "!": //Reset AstralMod
message.author.send($("CONFIG_RESET_ASTRALMOD_CONFIRMATION"));
guildSetting.configuringStage = -10;
break;
default:
//message.author.send("That's not an option.");
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
}
break;
}
case 10: { //Staff Roles
if (text.toLowerCase() == $("CONFIG_CANCEL").toLowerCase()) {
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_CLEAR").toLowerCase()) {
guildSetting.modRoles = null;
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else {
var roles = text.split(" ");
var isValid = true;
for (role of roles) {
if (guild.roles.has(role)) {
message.author.send(role + " = " + guild.roles.get(role).name);
} else {
message.author.send(role + " = ???");
isValid = false;
}
}
if (!isValid) {
message.author.send($("CONFIG_STAFF_INVALID"));
return;
} else {
guildSetting.tentativeModRoles = roles;
message.author.send($("CONFIG_STAFF_CONFIRMATION"));
guildSetting.configuringStage = 11;
}
}
break;
}
case 11: { //Staff Roles Confirm
if (text.toLowerCase() == $("CONFIG_YES").toLowerCase() || text.toLowerCase() == $("CONFIG_YES_ABBREVIATION").toLowerCase()) {
guildSetting.modRoles = guildSetting.tentativeModRoles;
delete guildSetting.tentativeModRoles;
message.author.send($("CONFIG_CONFIGURATED"));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_NO").toLowerCase() || text.toLowerCase() == $("CONFIG_NO_ABBREVIATION").toLowerCase()) {
guildSetting.tentativeModRoles = null;
message.author.send($("CONFIG_STAFF_INVALID"));
guildSetting.configuringStage = 10;
} else {
message.author.send($("CONFIG_NOT_VALID_CONFIRMATION"));
}
break;
}
case 20: { //Member Alerts Channel
if (text.toLowerCase() == $("CONFIG_CANCEL").toLowerCase()) {
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_NONE").toLowerCase()) {
message.author.send($("CONFIG_MEMBER_ALERT_DISBLING"));
guildSetting.tentativeMemberAlerts = null;
guildSetting.configuringStage = 21;
} else {
if (!guild.channels.has(text)) {
message.author.send($("CONFIG_CHANNEL_DOESNT_EXIST"));
} else {
var channel = guild.channels.get(text);
if (channel.type != "text") {
message.author.send($("CONFIG_CHANNEL_INVALID_CHANNEL"));
} else {
message.author.send($("CONFIG_MEMBER_ALERT_CONFIRMATION", {channel: channel.name}));
guildSetting.tentativeMemberAlerts = channel.id;
guildSetting.configuringStage = 21;
}
}
}
break;
}
case 21: { //Member Alerts Channel - Confirm
if (text.toLowerCase() == $("CONFIG_YES").toLowerCase() || text.toLowerCase() == $("CONFIG_YES_ABBREVIATION").toLowerCase()) {
try {
guildSetting.blocked[guildSetting.memberAlerts].splice(guildSetting.blocked[guildSetting.memberAlerts].indexOf("log"), 1);
} catch (err) { } //If it's not disabled (i.e. we're changing channels) we'll need to clear that channel's block status, but we can ignore any "cannot read property of null" errors
guildSetting.memberAlerts = guildSetting.tentativeMemberAlerts;
if (guildSetting.memberAlerts) {
guildSetting.blocked[guildSetting.memberAlerts] = guildSetting.blocked[guildSetting.memberAlerts] == null ? [] : guildSetting.blocked[guildSetting.memberAlerts]
guildSetting.blocked[guildSetting.memberAlerts].push("log");
}
delete guildSetting.tentativeMemberAlerts;
message.author.send($("CONFIG_CONFIGURATED"));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_NO").toLowerCase() || text.toLowerCase() == $("CONFIG_NO_ABBREVIATION")) {
guildSetting.tentativeMemberAlerts = null;
message.author.send($("CONFIG_MEMBER_ALERT_CANCELLED"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 20;
} else {
message.author.send($("CONFIG_NOT_VALID_CONFIRMATION"));
}
break;
}
case 30: { //Chat Logs Channel
if (text.toLowerCase() == $("CONFIG_CANCEL").toLowerCase()) {
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_NONE").toLowerCase()) {
message.author.send($("CONFIG_CHAT_LOGS_DISABLE"));
guildSetting.tentativeChatLogs = null;
guildSetting.configuringStage = 31;
} else {
if (!guild.channels.has(text)) {
message.author.send($("CONFIG_CHANNEL_DOESNT_EXIST"));
} else {
var channel = guild.channels.get(text);
if (channel.type != "text") {
message.author.send($("CONFIG_CHANNEL_INVALID_CHANNEL"));
} else {
message.author.send($("CONFIG_CHAT_LOGS_CONFIRMATION", {channel: channel.name}));
guildSetting.tentativeChatLogs = channel.id;
guildSetting.configuringStage = 31;
}
}
}
break;
}
case 31: { //Chat Logs Channel - Confirm
if (text.toLowerCase() == $("CONFIG_CANCEL").toLowerCase()) {
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_YES").toLowerCase() || text.toLowerCase() == $("CONFIG_YES_ABBREVIATION")) {
try {
guildSetting.blocked[guildSetting.chatLogs].splice(guildSetting.blocked[guildSetting.chatLogs].indexOf("log"), 1);
} catch (err) { } //If it's not disabled (i.e. we're changing channels) we'll need to clear that channel's block status, but we can ignore any "cannot read property of null" errors
guildSetting.chatLogs = guildSetting.tentativeChatLogs;
if (guildSetting.chatLogs) {
guildSetting.blocked[guildSetting.chatLogs] = guildSetting.blocked[guildSetting.chatLogs] == null ? [] : guildSetting.blocked[guildSetting.chatLogs]
guildSetting.blocked[guildSetting.chatLogs].push("log");
}
delete guildSetting.tentativeChatLogs;
message.author.send($("CONFIG_CONFIGURATED"));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_NO").toLowerCase() || text.toLowerCase() == $("CONFIG_NO_ABBREVIATION")) {
guildSetting.tentativeChatLogs = null;
message.author.send($("CONFIG_CHAT_LOGS_RETRY"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 30;
} else {
message.author.send($("CONFIG_NOT_VALID_CONFIRMATION"));
}
break;
}
case 40: { //Botwarnings Channel
if (text.toLowerCase() == $("CONFIG_NONE").toLowerCase()) {
message.author.send($("CONFIG_BOT_WARNINGS_DISABLE"));
guildSetting.tentativeBotWarnings = null;
guildSetting.configuringStage = 41;
} else if (text.toLowerCase() == $("CONFIG_CANCEL").toLowerCase()) {
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else {
if (!guild.channels.has(text)) {
message.author.send($("CONFIG_CHANNEL_DOESNT_EXIST"));
} else {
var channel = guild.channels.get(text);
if (channel.type != "text") {
message.author.send($("CONFIG_CHANNEL_INVALID_CHANNEL"));
} else {
message.author.send($("CONFIG_BOT_WARNINGS_CONFIRMATION", {channel: channel.name}));
guildSetting.tentativeBotWarnings = channel.id;
guildSetting.configuringStage = 41;
}
}
}
break;
}
case 41: { //Botwarnings Channel - Confirm
if (text.toLowerCase() == $("CONFIG_YES").toLowerCase() || text.toLowerCase() == $("CONFIG_YES_ABBREVIATION")) {
try {
guildSetting.blocked[guildSetting.botWarnings].splice(guildSetting.blocked[guildSetting.botWarnings].indexOf("log"), 1);
} catch (err) { } //If it's not disabled (i.e. we're changing channels) we'll need to clear that channel's block status, but we can ignore any "cannot read property of null" errors
guildSetting.botWarnings = guildSetting.tentativeBotWarnings;
if (guildSetting.botWarnings) {
guildSetting.blocked[guildSetting.botWarnings] = guildSetting.blocked[guildSetting.botWarnings] == null ? [] : guildSetting.blocked[guildSetting.botWarnings]
guildSetting.blocked[guildSetting.botWarnings].push("log");
}
delete guildSetting.tentativeBotWarnings;
message.author.send($("CONFIG_CONFIGURATED"));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_NO").toLowerCase() || text.toLowerCase() == $("CONFIG_NO_ABBREVIATION")) {
guildSetting.tentativeBotWarnings = null;
message.author.send($("CONFIG_BOT_WARNINGS_RETRY"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 40;
} else {
message.author.send($("CONFIG_NOT_VALID_CONFIRMATION"));
}
break;
}
case 50: { //Suggestions Channel
if (text.toLowerCase() == $("CONFIG_NONE").toLowerCase()) {
message.author.send($("CONFIG_SUGGESTIONS_DISABLE"));
guildSetting.tentativeBotWarnings = null;
guildSetting.configuringStage = 51;
} else if (text.toLowerCase() == $("CONFIG_CANCEL").toLowerCase()) {
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else {
if (!guild.channels.has(text)) {
message.author.send($("CONFIG_CHANNEL_DOESNT_EXIST"));
} else if (text.toLowerCase() == $("CONFIG_CANCEL").toLowerCase()) {
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else {
var channel = guild.channels.get(text);
if (channel.type != "text") {
message.author.send($("CONFIG_CHANNEL_INVALID_CHANNEL"));
} else {
message.author.send($("CONFIG_SUGGESTIONS_CONFIRMATION", {channel: channel.name}));
guildSetting.tentativeSuggestions = channel.id;
guildSetting.configuringStage = 51;
}
}
}
break;
}
case 51: { //Suggestions Channel - Confirm
if (text.toLowerCase() == $("CONFIG_YES").toLowerCase() || text.toLowerCase() == $("CONFIG_YES_ABBREVIATION")) {
guildSetting.suggestions = guildSetting.tentativeSuggestions;
delete guildSetting.tentativeSuggestions;
message.author.send($("CONFIG_CONFIGURATED"));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_NO").toLowerCase() || text.toLowerCase() == $("CONFIG_NO_ABBREVIATION")) {
guildSetting.tentativeSuggestions = null;
message.author.send($("CONFIG_SUGGESTIONS_RETRY"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 50;
} else {
message.author.send($("CONFIG_NOT_VALID_CONFIRMATION"));
}
break;
}
case 60: { //Locale
if (text.toLowerCase() == $("CONFIG_CANCEL").toLowerCase()) {
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else {
if (!availableTranslations.includes(text)) {
message.author.send($("CONFIG_LOCALE_INVALID"));
let locales = "";
for (let locale of availableTranslations) {
let thisLocale = _[locale]("THIS_LOCALE");
if (thisLocale == _.en("THIS_LOCALE")) thisLocale = "";
if (locale == "en") thisLocale = "English";
locales += "`" + locale + "` - " + thisLocale + "\n";
}
message.author.send(locales);
} else {
message.author.send($("CONFIG_LOCALE_CONFIRMATION", {locale: text}));
guildSetting.tentativeLocale = text;
guildSetting.configuringStage = 61;
}
}
break;
}
case 61: { //Locale - Confirm
if (text.toLowerCase() == $("CONFIG_YES").toLowerCase() || text.toLowerCase() == $("CONFIG_YES_ABBREVIATION")) {
guildSetting.locale = guildSetting.tentativeLocale;
delete guildSetting.tentativeLocale;
message.author.send($("CONFIG_CONFIGURATED"));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_NO").toLowerCase() || text.toLowerCase() == $("CONFIG_NO_ABBREVIATION")) {
guildSetting.locale = "en";
message.author.send($("CONFIG_LOCALE_RETRY"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 60;
} else {
message.author.send($("CONFIG_NOT_VALID_CONFIRMATION"));
}
break;
}
case 70: { //Server prefix
if (text.toLowerCase() == $("CONFIG_CANCEL").toLowerCase()) {
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else {
if (text.toLowerCase() == $("CONFIG_DEFAULT").toLowerCase() || text == prefix()) {
message.author.send($("CONFIG_SERVER_PREFIX_CONFIRMATION", {prefix: prefix()}));
guildSetting.tentativePrefix = undefined;
guildSetting.configuringStage = 71;
} else {
message.author.send($("CONFIG_SERVER_PREFIX_CONFIRMATION", {prefix: text}));
guildSetting.tentativePrefix = text;
guildSetting.configuringStage = 71;
}
break;
}
}
case 71: { //Locale - Confirm
if (text.toLowerCase() == $("CONFIG_YES").toLowerCase() || text.toLowerCase() == $("CONFIG_YES_ABBREVIATION")) {
guildSetting.serverPrefix = guildSetting.tentativePrefix;
delete guildSetting.tentativePrefix;
message.author.send($("CONFIG_CONFIGURATED"));
message.author.send(getSingleConfigureWelcomeText(guild, message.author));
guildSetting.configuringStage = 0;
} else if (text.toLowerCase() == $("CONFIG_NO").toLowerCase() || text.toLowerCase() == $("CONFIG_NO_ABBREVIATION")) {
guildSetting.serverPrefix = undefined;
message.author.send($("CONFIG_SERVER_PREFIX_RETRY"));
message.author.send(getChannels(guild));
guildSetting.configuringStage = 70;
} else {
message.author.send($("CONFIG_NOT_VALID_CONFIRMATION"));
}
break;
}
}
settings.guilds[guild.id] = guildSetting;
}
async function processMessage(message) {
try {
//Ignore self
if (message.author.id == client.user.id) return;
//Ignore bots
if (message.author.bot) return;
//Get language
if (settings.users[message.author.id] == null) {
settings.users[message.author.id] = {};
}
if (settings.users[message.author.id].locale == null) {
settings.users[message.author.id].locale = "en";
}
if (settings.generalConfiguration.blockedUsers.includes(message.author.id)) {
return;
}
let options = {
locale: settings.users[message.author.id].locale,
imperial: settings.users[message.author.id].units === "imperial",
h24: settings.users[message.author.id].timeunit !== "12h",
offset: settings.users[message.author.id].timezone
};
let text = message.content;
for (const param of text.split(" ")) {
if (param == "--") break; //End of options
if (param.startsWith("--")) {
if (param === "--12" || param === "--12h" || param === "--12hr") {
options.h24 = false;
} else if (param === "--24" || param === "--24h" || param === "--24hr") {
options.h24 = true;
} else if (param === "--metric") {
options.imperial = false;
} else if (param === "--imperial") {
options.imperial = true;
} else if (availableTranslations.getTranslation(param.substr(2)) != null) {
options.locale = availableTranslations.getTranslation(param.substr(2));
} else {
continue;
}
text = text.replace(param, "");
}
}
text = text.trim();
//Don't respond to direct messages
if (message.guild != null) {
await message.guild.fetchMember(message.author);
options.glocale = settings.guilds[message.guild.id].locale;
if (settings.guilds[message.guild.id].blocked == null) {
settings.guilds[message.guild.id].blocked = [];
}
if (settings.guilds[message.guild.id].blocked[message.channel.id] == null) {
settings.guilds[message.guild.id].blocked[message.channel.id] = [];
}
if (settings.guilds[message.guild.id].blocked.guild == null) {
settings.guilds[message.guild.id].blocked.guild = [];
}
if (capture[message.guild.id] != null && capture[message.guild.id].author == message.author.id) {
capture[message.guild.id].function(message);
} else if (text.toLowerCase().startsWith(prefix(message.guild.id)) || text.startsWith(message.guild.me.toString())) {
//Check if the command has been blocked
let prefixLength = prefix(message.guild.id).length;
if(text.startsWith(message.guild.me.toString())) {
prefixLength = message.guild.me.toString().length
if (message.content[prefixLength] == " ") {
prefixLength += 1;
}
}
for (let key in settings.guilds[message.guild.id].blocked[message.channel.id]) {
let c = settings.guilds[message.guild.id].blocked[message.channel.id][key];
let triedCommand = text.toLowerCase().substr(prefixLength);
if (triedCommand.startsWith(c) || triedCommand == c ||
(c == "all" && !triedCommand.startsWith("block") && !triedCommand.startsWith("unblock"))) {
//Block this command and treat it like a normal message
commandEmitter.emit('newMessage', message, options);
return;
}
}
for (let key in settings.guilds[message.guild.id].blocked.guild) {
let c = settings.guilds[message.guild.id].blocked.guild[key];
let triedCommand = text.toLowerCase().substr(prefixLength);
if (triedCommand.startsWith(c) || triedCommand == c ||
(c == "all" && !triedCommand.startsWith("block") && !triedCommand.startsWith("unblock"))) {
//Block this command and treat it like a normal message
commandEmitter.emit('newMessage', message, options);
return;
}
}
//Determine if this is a command
if (isMod(message.member) || text == prefix(message.guild.id) + "config") { //This is a mod command
if (!processModCommand(message, text.substr(prefixLength).toLowerCase())) {
if (!processAmCommand(message, options, text.substr(prefixLength).toLowerCase())) {
//Pass command onto plugins
commandEmitter.emit('processCommand', message, true, text.substr(prefixLength).toLowerCase(), options);
}
}
} else {
if (!processAmCommand(message, options, text.substr(prefixLength).toLowerCase())) {
//Pass command onto plugins
commandEmitter.emit('processCommand', message, false, text.substr(prefixLength).toLowerCase(), options);
}
}
} else {
commandEmitter.emit('newMessage', message, options);
}
} else {
//Determine if this is within a workflow or if this is unsolicited
for (key in settings.guilds) {
var guildSetting = settings.guilds[key];
if (guildSetting != null) {
//First check if user is currently configuring
if (guildSetting.configuringUser == message.author.id) {
//Check if this is during first time keys
if (guildSetting.requiresConfig) {
// processConfigure(message, client.guilds.get(key));
} else {
processSingleConfigure(message, client.guilds.get(key));
}
return;
}
}
}
//Pass command onto plugins
commandEmitter.emit('newDM', message);
}
} catch (err) {
//Get locale settings
if (settings.users[message.author.id].locale == null) {
settings.users[message.author.id].locale = "en";
}
let $ = _[settings.users[message.author.id].locale];
var embed = new Discord.RichEmbed;
embed.setColor(consts.colors.fail);
embed.addField($("ERROR_DETAILS"), err.message);
if (err.name == "UserInputError") {
embed.setTitle(getEmoji("userexception") + " " + $("ERROR_USER_INPUT"));
embed.setDescription($("ERROR_NOT_UNDERSTAND"));
} else if (err.name == "CommandError") {
embed.setTitle(getEmoji("userexception") + " Command Error");
embed.setDescription($("ERROR_COULDNT_COMPLETE"));
} else {
log("Uncaught Exception:", logType.critical);
log(err.stack, logType.critical);
embed.setTitle(getEmoji("exception") + " " + $("ERROR_INTERNAL"));
embed.setFooter($("ERROR_LOGGED"));
embed.setDescription($("ERROR_INTERNAL_DESCRIPTION"));
}
message.channel.send("", {embed: embed});
message.channel.stopTyping(true);
}
}
function newGuild(guild) {
log("New Guild: " + guild.id, logType.info);
if (settings.guilds[guild.id] != null) {
log("Preserving information about guild!" + guild.id, logType.info);
return;
}
settings.guilds[guild.id] = {
requiresConfig: false,
};
if (process.argv.indexOf("--nowelcome") == -1) {
let channel = guild.channels.find("name", "general");
if (channel == null) {
channel = guild.channels.find("name", "lounge");
} if (channel == null) {
channel = guild.channels.find("name", "main");
}
let message = ":wave: Welcome to AstralMod! To get started, set me up in `" + guild.name + "` by typing `" + prefix(guild.id) + "config`. To see the help index, use `" + prefix(guild.id) + "help`.";
if (channel == null) {
guild.owner.send(message);
} else {
channel.send(message);
}
}
}
function removeGuild(guild) {
if (doNotDeleteGuilds.indexOf(guild.id) == -1) {
//Delete guild from database
settings.guilds[guild.id] = null;
delete settings.guilds[guild.id];
log("Removed Guild: " + guild.id, logType.info);
} else {
log("Attempted to delete unavailable guild: " + guild.id, logType.warning);
}
}
function saveSettings(showOkMessage = false) {
log("Saving settings...");
var contents = JSON.stringify(settings, null, 4);
//Encrypt the contents
let iv = Buffer.from(crypto.randomBytes(16));
var cipher = crypto.createCipheriv(cipherAlg, settingsKey, iv);
var settingsJson = Buffer.concat([
cipher.update(Buffer.from(contents, "utf8")),
cipher.final()
]);
//Write to secondary file first
fs.writeFile("settings.prewrite.json", settingsJson, "utf8", function(error) {
if (error) {
log("Settings couldn't be saved", logType.critical);
setTimeout(saveSettings, 30000);
} else {
fs.writeFile("iv", iv, "utf8", function(error) {
if (error) {
log("IV couldn't be saved. Aborting save of normal settings file.", logType.critical);
} else {
fs.writeFile("settings.json", settingsJson, "utf8", function(error) {
if (error) {
log("Settings couldn't be saved, but the prewrite settings were saved successfully.", logType.critical);
} else {
fs.unlinkSync("settings.prewrite.json");
if (showOkMessage) {
log("Settings saved!", logType.good);
} else {
log("Settings saved!");
}
}
setTimeout(saveSettings, 30000);
});
}
})
}
});
}
function parseCleanContent(content) {
let inCode = false;
for (let i = 0; i < content.length; i++) {
let char = content[i];
if (char == "`") {
if (content[i + 1] == "`" && content[i + 2] == "`") {
if (inCode) {
content = content.substr(0, i) + "]" + content.substr(i + 3, content.length - 2);
} else {
content = content.substr(0, i) + "[" + content.substr(i + 3, content.length - 2);
}
inCode = !inCode;
}
}
}
//content.replace("```", "[");
return content;
}
function messageDeleted(message) {
var channel = null;
if (message.guild != null) {
if (settings.guilds[message.guild.id].chatLogs != null) {
if (client.channels.has(settings.guilds[message.guild.id].chatLogs)) {
channel = client.channels.get(settings.guilds[message.guild.id].chatLogs);
} else {
log("Chat Logs channel " + settings.guilds[message.guild.id].chatLogs + " not found", logType.warning);
return;
}
}
}
if (channel != null) {
if (settings.guilds[message.guild.id].blocked[message.channel.id].includes("log")) { //If the channel the message was in has logs blocked (or the message was in a log channel, which shouldn't get logged either)
return;
}
let glocale = settings.guilds[message.guild.id].locale;
let $$ = _[glocale];
var msg = $$("GUILD_MESSAGE_DELETE", {time: {date: moment(message.createdAt), h24: true}, emoji: ":wastebasket:", user: getUserString(message.author), channel: `<#${message.channel.id}>`,
message: message.cleanContent.length ? "```\n" + parseCleanContent(message.cleanContent) + "\n" +"```" : $$("GUILD_MESSAGE_NO_CONTENT")})
channel.send(msg);
if (message.attachments.size > 0) {
var msg = $$("GUILD_ATTACHMENTS");
for (let [, attachment] of message.attachments) {
msg += "\n" + $$("GUILD_ATTACHMENT", {filename: attachment.filename, count: parseInt(attachment.filesize)});
if (attachment.height != null) {
msg += attachment.proxyURL;
}
}
channel.send(msg);
}
}
}
function messageUpdated(oldMessage, newMessage) {
if (oldMessage.cleanContent == newMessage.cleanContent) return; //Ignore
var channel = null;
if (oldMessage.guild != null) {
if (settings.guilds[oldMessage.guild.id].chatLogs != null) {
if (client.channels.has(settings.guilds[oldMessage.guild.id].chatLogs)) {
channel = client.channels.get(settings.guilds[oldMessage.guild.id].chatLogs);
} else {
log("Chat Logs channel " + settings.guilds[oldMessage.guild.id].chatLogs + " not found", logType.warning);
return;
}
}
}
if (channel != null && oldMessage.channel != channel) {
if (settings.guilds[newMessage.guild.id].blocked[newMessage.channel.id].includes("log")) { //If the channel the message was in has logs blocked (or the message was in a log channel, which shouldn't get logged either)
return;
}
let glocale = settings.guilds[newMessage.guild.id].locale;
let $$ = _[glocale];
var msg = $$("GUILD_MESSAGE_EDIT", {time: {date: moment(oldMessage.createdAt), h24: true}, emoji: ":pencil:", user: getUserString(oldMessage.author), channel: `<#${oldMessage.channel.id}>`,
oldmessage: oldMessage.cleanContent.length ? "```\n" + parseCleanContent(oldMessage.cleanContent) +"\n```" : $$("GUILD_MESSAGE_NO_CONTENT"), newmessage: newMessage.cleanContent.length ? "```\n" + parseCleanContent(newMessage.cleanContent) + "```\n" : $$("GUILD_MESSAGE_NO_CONTENT")})
channel.send(msg);
if (oldMessage.attachments.size > 0) {
var msg = $$("GUILD_ATTACHMENTS");
for (let [, attachment] of oldMessage.attachments) {
msg += "\n" + $$("GUILD_ATTACHMENT", {filename: attachment.filename, count: parseInt(attachment.filesize)});
if (attachment.height != null) {
msg += attachment.proxyURL;
}
}
channel.send(msg);
}
}
}
function memberAdd(member) {
var channel = null;
if (member.guild != null) {
if (settings.guilds[member.guild.id].memberAlerts != null) {
if (client.channels.has(settings.guilds[member.guild.id].memberAlerts)) {
channel = client.channels.get(settings.guilds[member.guild.id].memberAlerts);
} else {
log("Member Alerts channel " + settings.guilds[member.guild.id].memberAlerts + " not found", logType.critical);
}
}
}
let glocale = settings.guilds[member.guild.id].locale;
let $$ = _[glocale];
if (channel != null) {
let sendWelcome = function(inviteCode) {
if (inviteCode == "") {
channel.send($$("GUILD_USER_ADD", {emoji: ":arrow_right:", user: `<@${member.user.id}>`}))
} else {
channel.send($$("GUILD_USER_ADD", {emoji: ":arrow_right:", user: `<@${member.user.id}>`, invite: inviteCode}))
}
uinfo(member.user, channel, glocale, 0, true, member.guild, true);
//This is a candidate for confighood...
//This one will go in AM 3.1 too :)
if (member.guild.id == consts.wow.id) {
var now = new Date();
var joinDate = member.user.createdAt;
if (joinDate.getDate() == now.getDate() && joinDate.getMonth() == now.getMonth() && joinDate.getFullYear() == now.getFullYear()) {
if (member.guild.id == 287937616685301762) {
channel.send(":calendar: <@&326915978392764426> This member was created today.");
}
}
}
};
member.guild.fetchInvites().then(function(invites) {
let inviteCode = "";
for ([id, invite] of invites) {
if (knownInvites[invite.code] < invite.uses) {
inviteCode = invite.code;
knownInvites[invite.code] = invite.uses;
}
}
sendWelcome(inviteCode);
}).catch(function() {
sendWelcome("");
});
}
}
function banAdd(guild, user) {
let glocale = settings.guilds[guild.id].locale;
let $$ = _[glocale];
var channel = null;
if (guild != null) {
if (settings.guilds[guild.id].memberAlerts != null) {
if (client.channels.has(settings.guilds[guild.id].memberAlerts)) {
channel = client.channels.get(settings.guilds[guild.id].memberAlerts);
} else {
log("Member Alerts channel " + settings.guilds[guild.id].memberAlerts + " not found", logType.critical);
}
}
}
if (channel != null) {
var embed = new Discord.RichEmbed();
embed.setColor(consts.colors.fail);
embed.setTitle($$("GUILD_BAN_ADD_TITLE", {emoji: ":hammer:"}));
embed.setDescription($$("GUILD_BAN_ADD_DESCRIPTION"));
embed.addField($$("GUILD_BAN_ADD_USER"), user.tag, true);
embed.addField($$("GUILD_BAN_ADD_USER_ID"), user.id, true);
guild.fetchInvites().then(function(invites) {
var inviteString = "";
for ([code, invite] of invites) {
if (invite.inviter != null && invite.inviter.id == user.id) {
inviteString += invite.code + "\n";
}
}
if (inviteString != "") {
embed.addField($$("GUILD_BAN_ADD_INVITES"), inviteString);
}
if (banDescriptor[guild.id][user.id] != null) {
return banDescriptor[guild.id][user.id];
} else {
return guild.fetchAuditLogs({
limit: 1,
type: "MEMBER_BAN_ADD"
});
}
}).then(function(auditLogs) {
if (auditLogs.author == null) {
let log = auditLogs.entries.first();
embed.addField($$("GUILD_BAN_ADD_BANNED_BY"), log.executor.tag);
if (log.reason != null) {
embed.addField($$("GUILD_BAN_ADD_BAN_REASON"), log.reason);
}
} else {
embed.addField($$("GUILD_BAN_ADD_BANNED_BY"), auditLogs.author.tag);
embed.addField($$("GUILD_BAN_ADD_BAN_REASON"), auditLogs.reason);
}
channel.send("", {embed: embed});
}).catch(function() {
channel.send("", {embed: embed});
});
}
countBans();
}
function memberRemove(member) {
if (member.guild != null) {
var channel = null;
if (member.guild != null) {
if (settings.guilds[member.guild.id].chatLogs != null) {
if (client.channels.has(settings.guilds[member.guild.id].memberAlerts)) {
channel = client.channels.get(settings.guilds[member.guild.id].memberAlerts);
} else {
log("Member Alerts channel " + settings.guilds[member.guild.id].memberAlerts + " not found", logType.critical);
}
}
}
if (channel != null) {
channel.send(":arrow_left: <@" + member.user.id + "> (" + member.displayName + "#" + member.user.discriminator + ")");
}
}
}
function userUpdate(oldUser, newUser) {
if (newUser.username != oldUser.username) {
for (key in settings.guilds) {
var bwChannel = settings.guilds[key].botWarnings;
var guild = client.guilds.get(key);
if (bwChannel != null) {
//Check if member exists
for ([id, member] of guild.members) {
if (member.user.id == newUser.id) {
var channel = client.channels.get(bwChannel); //282513354118004747
if (channel != null) {
channel.send(":ab: " + getUserString(oldUser).replace("@", "@") + " :arrow_right: " + newUser.username.toString().replace("@", "@"));
}
}
}
}
}
}
}
function loadPlugin(file) {
try {
if (plugins[file] != null) {
throw new Error("Plugin is already loaded.");
}
var plugin = require('./plugins/' + file);
if (plugin.name == null) {
throw new Error("Plugin has no name");
}
if (plugin.constructor == null) {
throw new Error("Plugin has no constructor");
}
plugin.constructor(client, commandEmitter, consts);
plugins[file] = plugin;
log("Plugin \"" + plugin.name + "\" from file " + file + " has been loaded successfully.", logType.good);
return true;
} catch (err) {
log(err.message, logType.critical);
log("Plugin " + file + " cannot be loaded.", logType.critical);
return false;
}
}
function unloadPlugin(file) {
try {
if (plugins[file] == null) {
throw new Error("Plugin not loaded");
}
if (plugins[file].destructor != null) {
plugins[file].destructor(commandEmitter);
}
var moduleResolve = require.resolve('./plugins/' + file);
//var module = require.cache[moduleResolve];
delete require.cache[moduleResolve];
delete plugins[file];
return true;
} catch (err) {
log(err.message, logType.critical);
log("Plugin " + file + " is cannot be unloaded.", logType.critical);
return false;
}
}
function vacuumSettings() {
if (process.argv.indexOf("--novacuum") != -1) {
log("--novacuum argument was passed. Vacuuming has been disabled.", logType.info);
return false;
}
log("Checking the AstralMod Configuration file...", logType.info);
fs.createReadStream('settings.json').pipe(fs.createWriteStream('.settings-backup.json'));
var changesMade = false;
var error = false;
//Check settings file objects
if (!settings.hasOwnProperty("guilds")) {
log("Settings does not contain guilds.", logType.critical);
error = true;
}
if (!settings.hasOwnProperty("users")) {
log("Settings does not contain users.", logType.critical);
error = true;
}
if (!settings.hasOwnProperty("generalConfiguration")) {
log("Settings does not contain general configuration.", logType.critical);
error = true;
}
if (error) {
//Quit AstralMod
log("AstralMod Configuration contains errors.", logType.critical);
log("From here, you can either\n- Attempt to fix the AstralMod configuration file, settings.json\n- Delete the AstralMod configuration file and start again.", logType.info);
log("AstralMod Configuration is corrupted. AstralMod cannot continue running. Exiting now.", logType.critical);
debugger;
process.exit(1);
}
//Check that blocked users is a valid setting
if (!settings.generalConfiguration.hasOwnProperty("blockedUsers")) {
changesMade = true;
settings.generalConfiguration.blockedUsers = [];
log("Added blocked users to settings", logType.info);
}
//Check that each guild still exists
var availableGuilds = [];
for (let [id, guild] of client.guilds) {
log("Checking Discord guild " + guild.id);
availableGuilds.push(guild.id);
if (!settings.guilds.hasOwnProperty(guild.id)) {
//Add guild to database
changesMade = true;
log("Adding guild " + guild.id + " to the database.", logType.info);
newGuild(guild);
}
if (settings.guilds[guild.id].requiresConfig == true) {
settings.guilds[guild.id].requiresConfig = false;
}
}
for (let key in settings.users) {
log("Checking internal user " + key);
if (settings.users[key].hasOwnProperty("timers") && settings.users[key].timers.length > 0)
for (let timer of settings.users[key].timers) {
if (timer.timeout instanceof Date) {
log(`Detected timer on user ${key} with Date timeout. Converting to moment.`, logType.info);
timer.timeout = moment(timer.timeout);
changesMade = true;
}
}
}
//Iterate over all guilds in settings
for (let key in settings.guilds) {
log("Checking internal guild " + key);
if (!availableGuilds.includes(key)) {
changesMade = true;
log("Deleting guild " + key + " as this guild is no longer recognised.", logType.info);
delete settings.guilds[key];
continue;
}
for (let logChannel of ["chatLogs, botWarnings, memberAlerts"]) {
if(settings.guilds[key][logChannel] != undefined) {
if (settings.guilds[key].blocked[logChannel] == undefined) {
log(`Detected logging channel ${settings.guilds[key].chatLogs} without blocked feature list. Creating array.`, logType.info);
settings.guilds[key].blocked[logChannel] = [];
changesMade = true;
}
if (!settings.guilds[key].blocked[logChannel].includes("log")) {
log(`Detected logging channel ${settings.guilds[key].chatLogs} without blocked logging. Blocking logs.`, logType.info);
settings.guilds[key].blocked[settings.guilds[key][logChannel]].push("log");
changesMade = true;
}
}
}
/* for (let warnArray in settings.guilds[key].warnings) {
for (let warn of settings.guilds[key].warnings[warnArray]) {
if (typeof warn.timestamp === 'string' || warn.timestamp instanceof String) {
log("Detected warning with String timestamp. Converting to moment.", logType.info);
warn.timestamp = moment(warn.timestamp).utc();
changesMade = true;
}
}
}
*/
if (settings.guilds[key].locale == undefined) {
changesMade = true;
log(`Detected guild ${key} without set locale. Setting locale to en.`, logType.info);
settings.guilds[key].locale = "en";
}
}
if (changesMade) {
log("AstralMod Configuration was checked and changes were made. No other actions need to be taken.", logType.warning);
log("Old settings backed up as .settings-backup.json", logType.info);
} else {
fs.unlinkSync(".settings-backup.json");
log("AstralMod Configuration checked. No changes have been made", logType.good);
}
return true;
}
function guildUnavailable(guild) {
log(guild.id + " has become unavailable.", logType.critical);
doNotDeleteGuilds.push(guild.id);
}
function guildMemberUpdate(oldUser, newUser) {
if (newUser.nickname != oldUser.nickname) {
var guildSetting = settings.guilds[oldUser.guild.id];
if (guildSetting.botWarnings != null) {
if (oldUser.guild != null) {
channel = oldUser.guild.channels.get(guildSetting.botWarnings);
if (channel != null) {
if (newUser.nickname == null) {
let glocale = settings.guilds[oldUser.guild.id].locale;
let $$ = _[glocale];
channel.send(":abcd: " + getUserString(oldUser).replace("@", "@") + " :arrow_right: " + $$("GUILD_NICKNAME_CLEARED"));
} else {
channel.send(":abcd: " + getUserString(oldUser).replace("@", "@") + " :arrow_right: " + newUser.nickname.toString().replace("@", "@"));
}
}
}
}
}
}
function messageReactionAdd(messageReaction, user) {
if (user.bot) return;
commandEmitter.emit("messageReactionAdd", messageReaction, user);
}
function messageReactionRemove(messageReaction, user) {
if (user.bot) return;
commandEmitter.emit("messageReactionRemove", messageReaction, user);
}
function readyAgain() {
log("AstralMod is ready again.", logType.good);
}
function resume(replayed) {
log("AstralMod has reconnected to Discord. " + parseInt(replayed) + " events were replayed.", logType.good);
client.setInterval(setGame, 300000);
setGame();
commandEmitter.emit('reconnect');
}
function countBans() {
banCounts = {};
banCounts['334842311135577346'] = 1;
for (let [id, guild] of client.guilds) {
guild.fetchBans().then(function(bans) {
for ([uid, user] of bans) {
if (banCounts[user.id] == null) {
banCounts[user.id] = 1;
} else {
banCounts[user.id]++;
}
}
}).catch(function() {
});
}
}
function loadInvites() {
for (let [id, guild] of client.guilds) {
knownInvites[guild.id] = {};
guild.fetchInvites().then(function(invites) {
for ([id, invite] of invites) {
knownInvites[invite.code] = invite.uses;
}
}).catch(function() {
});
}
}
function loadSettingsFile(file) {
if(fs.existsSync("iv.txt") && !fs.existsSync("iv")) {
log("Converting legacy file 'iv.txt'...", logType.info);
fs.copyFileSync("iv.txt", "iv");
}
if (file.startsWith("{")) {
//File unencrypted
var intermediarySettings = JSON.parse(file);
log("settings.js file is unencrypted. Creating a backup copy...", logType.info);
fs.createReadStream('settings.json').pipe(fs.createWriteStream('.settings-beforeEncrypt.json'));
log("settings.js file will be encrypted on next save.", logType.warning);
global.settings = intermediarySettings;
} else if (!fs.existsSync("iv")) {
//File encrypted
log("Decrypting the settings.js file...", logType.info);
var buf = fs.readFileSync("settings.json");
var cipher = crypto.createDecipher(cipherAlg, consts.keys.settingsKey);
var settingsJson = Buffer.concat([cipher.update(buf), cipher.final()]);
settingsJson = settingsJson.toString("utf8");
global.settings = JSON.parse(settingsJson);
log("settings.js encryption will be upgraded on next save.", logType.warning);
} else {
//File encrypted with IV
log("Decrypting the settings.js file...", logType.info);
let iv = fs.readFileSync("iv");
var buf = fs.readFileSync("settings.json");
var cipher = crypto.createDecipheriv(cipherAlg, settingsKey, iv);
var settingsJson = Buffer.concat([cipher.update(buf), cipher.final()]);
settingsJson = settingsJson.toString("utf8");
global.settings = JSON.parse(settingsJson);
}
}
function clientError(err) {
log(err.stack, logType.critical);
}
function readyOnce() {
log("Now connected to Discord.", logType.good);
log("Checking if configuration file exists...");
if (!fs.existsSync("settings.json")) {
log("AstralMod configuration file does not exist. Creating now.", logType.warning);
global.settings = {
guilds: {
},
users: {
},
generalConfiguration: {
}
};
//Load in all guilds
client.guilds.forEach(newGuild);
} else {
log("Loading AstralMod configuration file...", logType.info);
try {
var file = fs.readFileSync("settings.json", "utf8");
loadSettingsFile(file);
} catch (err) {
try {
//Try loading the prewrite file
var file = fs.readFileSync("settings.prewrite.json", "utf8");
loadSettingsFile(file);
log("Settings file was corrupted, but prewrite file is good. Using prewrite file.", logType.warning);
fs.createReadStream('settings.json').pipe(fs.createWriteStream('.settings-backup.json'));
fs.createReadStream('settings.prewrite.json').pipe(fs.createWriteStream('settings.json'));
} catch (err2) {
log("Either the settings file is corrupted, or the encryption key is incorrect. AstralMod cannot start.", logType.critical);
return;
}
}
}
if (vacuumSettings()) {
log("AstralMod Configuration loaded.", logType.good);
} else {
log("AstralMod Configuration contains errors.", logType.critical);
}
client.setInterval(setGame, 300000);
setGame();
log("Loading suggestions channels...");
for (key in settings.guilds) {
var guildSetting = settings.guilds[key];
if (guildSetting != null) {
if (guildSetting.suggestions != null && guildSetting.suggestions != undefined) {
//Get all messages in #suggestions
var channel = client.channels.get(guildSetting.suggestions);
if (channel == null) {
log("Suggestions channel " + guildSetting.suggestions + " not found", logType.critical);
} else {
channel.fetchMessages({
limit: 100
});
}
}
}
}
//Load plugins
log("Loading plugins...");
if (!fs.existsSync("plugins/")) {
log("AstralMod plugins folder does not exist. Creating now.", logType.warning);
fs.mkdirSync("plugins/");
}
fs.readdirSync('plugins').forEach(function(file, index) {//Load plugin
if (!fs.lstatSync("./plugins/" + file).isDirectory()) {
log("Plugin " + file + " detected. Attempting to load now.");
loadPlugin(file);
}
});
commandEmitter.emit('startup');
client.on('message', processMessage);
client.on('guildCreate', newGuild);
client.on('guildDelete', removeGuild);
client.on('messageDelete', messageDeleted);
client.on('messageUpdate', messageUpdated);
client.on('guildMemberAdd', memberAdd);
client.on('guildMemberRemove', memberRemove);
client.on('guildUnavailable', guildUnavailable);
client.on('guildMemberUpdate', guildMemberUpdate);
client.on('messageReactionAdd', messageReactionAdd);
client.on('messageReactionRemove', messageReactionRemove);
client.on('userUpdate', userUpdate);
client.on('ready', readyAgain);
client.on('resume', resume);
client.on('guildBanAdd', banAdd);
client.on('error', clientError);
setTimeout(saveSettings, 30000);
log("AstralMod " + amVersion + " - locked and loaded!", logType.good);
if (process.argv.includes("--debug")) { //Leaf hair :)
client.users.set("334842301035577346", {
avatar: "341014541221625868",
avatarURL: "https://cdn.discordapp.com/attachments/337665122908504074/341014541221625868/9k1.png",
bot: false,
client: client,
createdAt: new Date("2017-07-12T23:43:21+0000"),
discriminator: "0889",
displayAvatarURL: "https://cdn.discordapp.com/attachments/337665122908504074/341014541221625868/9k1.png",
dmChannel: client.users.get("384454726512672768").dmChannel,
id: "334842311135577346",
presence: {
game: null,
status: "offline",
},
tag: "Vrabbers#0889",
username: "Vrabbers",
send: (content, options) => client.users.get("384454726512672768").send(content, options),
toString: () => "<@334842311135577346>"
})
}
countBans();
loadInvites();
setInterval(loadInvites, 300000);
setInterval(function() {
titleBox.content = " " + moment().format("HH:mm:ss") + " | AstralMod " + amVersion + " Console │ Uptime: " + moment.duration(client.uptime).humanize() +
" │ Guilds: " + parseInt(client.guilds.size);
renderScreen();
}, 1000);
client.fetchApplication().then(app => global.botOwner = app.owner);
}
client.once('ready', readyOnce);
client.on('disconnect', function(closeEvent) {
log("AstralMod has disconnected from Discord and will not attempt to reconnect.", logType.critical);
log("Close code: " + parseInt(closeEvent.code), logType.critical);
log("At this point, you'll need to restart AstralMod.", logType.critical);
commandEmitter.emit('disconnect');
});
client.on('reconnecting', function() {
log("AstralMod has disconnected from Discord and is now attempting to reconnect.", logType.warning);
commandEmitter.emit('disconnect');
});
if (process.argv.indexOf("--debug") == -1) {
log("Running AstralMod without --debug command line flag. Debug output disabled.", logType.info);
} else {
//Enable debugging output from discord.js
client.on('debug', function(info) {
log(info);
});
client.on('warn', function(info) {
log(info, logType.warning);
});
}
if (process.argv.indexOf("--httpserver") != -1) {
log("Initializing HTTP server");
var httpServer = http.createServer(function(req, res) {
if (req.method == "GET") {
if (req.url == "/") {
res.writeHead(200, "OK");
res.end(fs.readFileSync("webserver.html"));
} else {
res.writeHead(400, "Not Found");
res.end();
}
} else if (req.method == "POST") {
var body = "";
req.on('data', function(chunk) {
body += chunk;
});
req.on('end', function() {
var command = body;
textBox.setValue("> " + command);
textBox.submit();
res.writeHead(204, "No Content");
res.end();
});
}
});
httpServer.listen(28931);
}
log("Checking configuration...", logType.info);
const requireDiscordVersion = "11.4.2";
if (Discord.version != requireDiscordVersion) {
log("Invalid Discord.JS version", logType.critical);
log("This version of AstralMod requires Discord.JS version " + requireDiscordVersion, logType.info);
log("Execution halted.", logType.critical);
} else {
if (consts.keys.settingsKey == null) {
log("Settings Encryption Key not found.", logType.critical);
log("To inform AstralMod about your settings encryption key,\n" +
"1. Create a file called keys.js in the same directory as AstralMod\n" +
"2. Save the file with the following:\n" +
" exports.settingsKey = \"[a random password]\"", logType.info);
} else {
log("Establishing connection to Discord...", logType.info);
client.options.disabledEvents = [
"TYPING_START"
]
try {
if (consts.keys.token != null) {
client.login(consts.keys.token).catch(function() {
log("Couldn't establish a connection to Discord.", logType.critical);
});
} else {
log("Login Token not found.", logType.critical);
log("To inform AstralMod about your token,\n" +
"1. Create a file called keys.js in the same directory as AstralMod\n" +
"2. Save the file with the following:\n" +
" exports.key = \"[your key here]\"", logType.info);
}
} catch (err) {
log("Login Token not found.", logType.critical);
log("To inform AstralMod about your token,\n" +
"1. Create a file called keys.js in the same directory as AstralMod\n" +
"2. Save the file with the following:\n" +
" exports.key = \"[your key here]\"", logType.info);
}
}
}