-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
238 lines (198 loc) · 11.2 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// This is where the magic starts.
// If you haven't yet, please read README.md
// It'll explain how to create and setup a .env file, and everything else recommended for you to add.
// Comments will be everywhere (hopefully throughout every file) explaining how everything works and what it all does
// along with things you may want to remove :)
// If you have any questions, feel free to contact me on Discord. Lawlzer#4013
// Invite Link for the bot: https://discordapp.com/oauth2/authorize?client_id=206980947298615297&scope=bot
console.log('The bot is in index.js');
const production = true; // set to true if it's the "production" version of your bot
const devTestingGuildId = '547192605927145481'; // set to the id of your TESTING server. This IS important.
const devUserId = '206980947298615297';
// should be the GUILD id, not the CHANNEL id.
const commands = require('./commands/allCommands');
const databaseController = require('./lib/database');
const exampleController = require('./lib/example');
const mongoose = require('mongoose');
const Discord = require('discord.js');
const dotenv = require('dotenv');
dotenv.load({ path: '.env' });
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
mongoose.set('useNewUrlParser', true);
mongoose.set('useUnifiedTopology', true);
mongoose.connect(process.env.MONGODB_URI);
mongoose.connection.on('error', (err) => {
console.error(err);
console.log('%s MongoDB connection error. Please make sure MongoDB is running.');
process.exit();
});
const bot = new Discord.Client();
var messageDeveloper;
bot.on('ready', () => { // When our bot is ready:
bot.user.setActivity("with myself");
// https://discord.js.org/#/docs/main/stable/class/ClientUser?scrollTo=setActivity
// bot.user.setActivity('YouTube', { type: 'WATCHING' })
// .then(presence => console.log(`Activity set to ${presence.game ? presence.game.name : 'none'}`))
// .catch(console.error);
console.log('Bot running.');
// If you're not me (hi!), you'll probably want to either delete this, or leave it, if you want messages when something goes wrong.
bot.fetchUser(devUserId, false).then((user) => {
if (!user) {
console.log('The user could not be found. Are you sure you\'re in the same server as the bot?'); // possibly not needed text, depending on how mass scale your bot is.
return;
}
messageDeveloper = user;
});
});
bot.on('messageReactionAdd', async (reaction, user) => {
if (user.bot) { return; }
// we need to make sure the reaction isn't from the bot
const nerdDumpEmojiId = await databaseController.returnNerdDumpEmojiId();
if (reaction.emoji.id != nerdDumpEmojiId) {
// we need the correct reaction
return;
}
var allObjects = await databaseController.returnNerdDumpInfo();
var correctObject = null;
for (let i = 0; i < allObjects.length; i++) {
if (allObjects[i].id == reaction.message.id) { // this is the correct element, we found it, now we have to do stuff with this
correctObject = allObjects[i];
}
}
if (!correctObject) {
// somebody probably reacted to a non-bot message with your custom emoji
// or they reacted after the thing was deleted from our saved array
if (reaction.message.editable) { // they reacted to a message by the bot, BUT they waited too long, OR the bot was restarted inbetween them running the command and trying to react.
var embed = reaction.message.embeds[0] // we can't use the correctObject.basicEmbed, as that doesn't exist.. because we couldn't find the correctObject
console.log(reaction.message.embeds[0].footer);
// embed.setFooter();
console.log(embed);
reaction.message.edit('Nerd Dump Error: The nerd dumped too late. The nerd needs to dump within ' + await databaseController.returnNerdDumpTimeOut() + ' seconds.');
return; // technically useless return.. but it looks better, and signifies that there *could* be lower code
}
// they reacted to a message that isn't by the bot.... no response is needed
return;
}
const currentTime = Date.now();
var embed = correctObject.basicEmbed;
embed.setFooter(
'NERD DUMP ACTIVATED!' +
'\nDiscord message sent --> Discord message reacted to time: ' + (correctObject.discordSecondMessageTime - correctObject.discordInitialMessageTime) + 'ms.' +
'\nBot message recieved --> Bot message sent (total time for the bot to handle the message)' + (correctObject.initialMessageStarted - correctObject.initialMessageSent) + 'ms.'
);
reaction.message.edit(embed)
})
bot.on('message', async message => {
if (message.author.bot) {
return; //if the author of the message is the bot, do nothing.
}
if (!message.guild) { //If the message is sent via DMs.
message.reply('Please do not message this bot in DMs. Please do !help in a public channel, or add Lawlzer on Discord for help. Lawlzer#4013')
return;
} // lots of commands don't work if you message the bot in DMs, so it's just disabled overall
// all of the databases, by default, are created based on the server ID (aka guild ID) - so there aren't any databases in DMs
if (message.guild.id == devTestingGuildId && production) {
console.log('In dev testing server, but production is enabled. Message ignored.');
return;
}
if (message.guild.id != devTestingGuildId && !production) {
console.log('In dev testing server, but this is the production bot. Message ignored.')
return;
}
// this handles the command itself, and handles all of the stuff for running the command itself
await (async function executeCommand() {
message.messageRecievedByBotTime = Date.now(); // slightly jank, but this will be used in the nerd dump information
const database = await databaseController.getOrCreateDatabase(message.guild.id);
var commandPrefix = database.commandPrefix;
var commandName = message.content.toLowerCase();
// sets the name of the command
if (!commandName.startsWith(commandPrefix)) {
return;
}
// makes sure the command starts with the correct prefix
commandName = commandName.replace(commandPrefix, ''); // get rid of the prefix
commandName = commandName.split(' ');
if (commandName[0] == '') { commandName.shift(); } // if we have a command with a space inbetween the prefix and the command
// e.g "! ping" - this will remove the space
// the commandName is only the first word, so we split it up by spaces, then take the first word. (needed if we have args/whatever)
commandName = commandName[0];
var argsLowercase = message.content.toLowerCase();
argsLowercase = argsLowercase.replace(commandPrefix, '');
argsLowercase = argsLowercase.replace(commandName, '');
argsLowercase = argsLowercase.split(' ');
// sets up the argsLowercase (removes prefix, makes everything lowercase, removes the commandName, so everything we have left are the arguments)
if (await exampleController.findUserCommand(bot, message, database, commandName) == true) {
// this command will return "true" if it finds a user created command and will then send the message to the channel
// look at /commands/example.js to see the command setup, and /lib/example.js for the command itself
return;
}
// this is kind of jank, I'll be honest.
// The names of everything in /commands/database.js are all capitalized (uppercase and stuff), but the problem is, we want commands to
// be case insensitive.. But we still want the names capitalized (or camelCase, or whatever) when the user runs !help
// And *I couldn't figure out a way* to make the names of everything in /commands/database.js capitalized there, but lowercase here...
// so, we get just the NAMES of every object there
var commandNames = Object.keys(convertKeysToLowerCase(commands)); // get all the names in lowercase, so we can search them
// and we make sure this is a command that's included there (this is lowercase!)
if (!commandNames.includes(commandName)) {
return;
}
// and then we save the INDEX of the command where the correct name is
// now that I think about it, I'm pretty sure I could've merged the 3 lines above and the lower one, but this looks a lot better
var indexOfCommand = commandNames.indexOf(commandName); // get the INDEX of the correct command, then use that for everything else, since capitalization is probably wrong
// then we make an array of every single command...
var commandsArray = [];
for (var i in commands) { // make a commandsArray so we can go to the index of the command
commandsArray.push(commands[i]);
}
// and then we find that command, where it's capitalized! It works. Don't question the jank.
const command = commandsArray[indexOfCommand];
if (!!command.requirements) { // this deals with command requirements, and makes sure all of the command requirements are true
for (let i = 0; i <= command.requirements.length - 1; i++) {
if (!await command.requirements[i](bot, message, argsLowercase, content)) {
console.log('The requirement: "' + commandName + '" has failed');
return;
}
}
}
// Everything under here runs the command itself
try {
var content = message.content;
content = content.replace(commandPrefix, '');
content = content.replace(commandName, '');
if (argsLowercase[0] == '') { argsLowercase.shift(); } // if the 0th array in the array is empty, this removes it.
// it happens a lot (or atleast used to), and this was my quick-fix. Probably should check this again in the future.
var result = await command.execute(bot, message, argsLowercase, content);
if (!!result && result.hasOwnProperty('then') && typeof result.then === 'function') {
result = await result;
}
} catch (e) {
// if there's an error, this will return a message to the user, and if it's production (production = true), it'll even message you in DMs! (if you're in the server)
await databaseController.sendErrorEmbed(bot, message, 'ERROR', 'You should never see this... Uhhh.. Sorry. To sate your curiousity, here\'s the error.\n' + e.message);
if (production) {
console.log('Error found in production code... That\'s not good.\n' + e.message);
if (messageDeveloper) { // if you have a popular bot, you might not be in the same server as the bot, then this would throw a massive error, because it can't find your user, based on your ID.
await databaseController.sendErrorEmbed(bot, message, 'ERROR', 'Error found in production code... That\'s not good.\n' + e.message);
}
}
// if we have any
}
})();
});
const token = process.env.DISCORD_BOT_SECRET;
bot.login(token);
function convertKeysToLowerCase(obj) {
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames
var output = {};
for (i in obj) {
if (Object.prototype.toString.apply(obj[i]) === '[object Object]') {
output[i.toLowerCase()] = convertKeysToLowerCase(obj[i]);
} else if (Object.prototype.toString.apply(obj[i]) === '[object Array]') {
output[i.toLowerCase()] = [];
output[i.toLowerCase()].push(convertKeysToLowerCase(obj[i][0]));
} else {
output[i.toLowerCase()] = obj[i];
}
}
return output;
};