· 6 years ago · Jun 27, 2019, 07:12 PM
1const Discord = require(`discord.js`);
2const client = new Discord.Client();
3
4var _ = require(`underscore`);
5var fs = require(`fs`);
6const mysql = require(`mysql2`);
7const editJsonFile = require(`edit-json-file`);
8const cryptoRandomString = require(`crypto-random-string`);
9const moment = require(`moment`);
10
11const config = require(`./config.json`);
12const locale = require(`./locale.json`);
13const channelsData = require(`./channels.json`);
14
15var bannedUsers = require(`./banned_users.json`);
16
17var allowedRolesFile = editJsonFile(`./allowed_roles.json`);
18var badWordsFile = editJsonFile(`./bad_words.json`);
19var bannedUsersFile = editJsonFile(`./banned_users.json`);
20var mutedFile = editJsonFile(`./muted.json`);
21var channelsFile = editJsonFile(`./channels.json`);
22var allowedRolesFile = editJsonFile(`./allowed_roles.json`);
23
24var deletedByBot = 0;
25
26// Connecting to database
27const connection = mysql.createConnection({
28 host: config.host,
29 user: config.user,
30 password: config.password,
31 database: config.database,
32 multipleStatements: true,
33});
34connection.connect(function (err, results) {
35 console.log(`Established MySQL database connection.`);
36 if (err) {
37 throw err;
38 }
39});
40
41// Functions
42function setupTables() {
43 connection.query(
44 `CREATE TABLE IF NOT EXISTS users
45 (
46 userID VARCHAR(25) NOT NULL,
47 guildID VARCHAR(25) NOT NULL,
48 username VARCHAR(255) NOT NULL,
49 avatar VARCHAR(50),
50 exist bit DEFAULT 1,
51 timestamp DATETIME NOT NULL,
52 updated timestamp NOT NULL,
53 PRIMARY KEY (userID, guildID)
54 )
55 CHARACTER SET 'utf8mb4'
56 COLLATE 'utf8mb4_general_ci';`,
57 function (err, results) {
58 if (err => {
59 throw err;
60 });
61 }
62 );
63 connection.query(
64 `CREATE TABLE IF NOT EXISTS log_nickname
65 (
66 id int NOT NULL AUTO_INCREMENT,
67 userID VARCHAR(25) NOT NULL,
68 guildID VARCHAR(25) NOT NULL,
69 new VARCHAR(255),
70 old VARCHAR(255),
71 timestamp DATETIME NOT NULL,
72 PRIMARY KEY (id)
73 )
74 CHARACTER SET 'utf8mb4'
75 COLLATE 'utf8mb4_0900_ai_ci';`,
76 function (err, results) {
77 if (err => {
78 throw err;
79 });
80 }
81 );
82 connection.query(
83 `CREATE TABLE IF NOT EXISTS messageTypes
84 (
85 id int NOT NULL,
86 type VARCHAR(100),
87 PRIMARY KEY (id)
88 )
89 CHARACTER SET 'utf8mb4'
90 COLLATE 'utf8mb4_general_ci';`,
91 function (err, results) {
92 if (err => {
93 throw err;
94 });
95 }
96 );
97 connection.query(
98 `CREATE TABLE IF NOT EXISTS log_username
99 (
100 id int NOT NULL AUTO_INCREMENT,
101 userID VARCHAR(25) NOT NULL,
102 guildID VARCHAR(25) NOT NULL,
103 new VARCHAR(255),
104 old VARCHAR(255),
105 timestamp DATETIME NOT NULL,
106 PRIMARY KEY (id)
107 )
108 CHARACTER SET 'utf8mb4'
109 COLLATE 'utf8mb4_0900_ai_ci';`,
110 function (err, results) {
111 if (err => {
112 throw err;
113 });
114 }
115 );
116 connection.query(
117 `CREATE TABLE IF NOT EXISTS voiceTypes
118 (
119 id int NOT NULL,
120 guildID VARCHAR(25) NOT NULL,
121 type VARCHAR(100),
122 PRIMARY KEY (id)
123 )
124 CHARACTER SET 'utf8mb4'
125 COLLATE 'utf8mb4_general_ci';`,
126 function (err, results) {
127 if (err => {
128 throw err;
129 });
130 }
131 );
132 connection.query(
133 `CREATE TABLE IF NOT EXISTS log_voice
134 (
135 id int NOT NULL AUTO_INCREMENT,
136 userID VARCHAR(25) NOT NULL,
137 guildID VARCHAR(25) NOT NULL,
138 newChannelID VARCHAR (50),
139 newChannel VARCHAR (50),
140 oldChannelID VARCHAR (50),
141 oldChannel VARCHAR (50),
142 type int,
143 timestamp DATETIME NOT NULL,
144 PRIMARY KEY (id),
145 FOREIGN KEY (type) REFERENCES voiceTypes(id)
146 )
147 CHARACTER SET 'utf8mb4'
148 COLLATE 'utf8mb4_general_ci';`,
149 function (err, results) {
150 if (err => {
151 throw err;
152 });
153 }
154 );
155 connection.query(
156 `CREATE TABLE IF NOT EXISTS log_guildjoin
157 (
158 userID VARCHAR(25) NOT NULL,
159 guildID VARCHAR(25) NOT NULL,
160 timestamp DATETIME
161 )
162 CHARACTER SET 'utf8mb4'
163 COLLATE 'utf8mb4_0900_ai_ci';`,
164 function (err, results) {
165 if (err => {
166 throw err;
167 });
168 }
169 );
170 connection.query(
171 `CREATE TABLE IF NOT EXISTS log_guildleave
172 (
173 userID VARCHAR(25) NOT NULL,
174 guildID VARCHAR(25) NOT NULL,
175 timestamp DATETIME
176 )
177 CHARACTER SET 'utf8mb4'
178 COLLATE 'utf8mb4_0900_ai_ci';`,
179 function (err, results) {
180 if (err => {
181 throw err;
182 });
183 }
184 );
185 connection.query(
186 `CREATE TABLE IF NOT EXISTS log_guildbans
187 (
188 ID INT NOT NULL AUTO_INCREMENT,
189 userID VARCHAR(25),
190 guildID VARCHAR(25) NOT NULL,
191 actioner VARCHAR(25),
192 description TEXT,
193 identifier VARCHAR(10),
194 isDeleted BIT,
195 timestamp DATETIME,
196 updated DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
197 PRIMARY KEY (ID)
198 )
199 CHARACTER SET 'utf8mb4'
200 COLLATE 'utf8mb4_0900_ai_ci';`,
201 function (err, results) {
202 if (err => {
203 throw err;
204 });
205 }
206 );
207 connection.query(
208 `CREATE TABLE IF NOT EXISTS log_guildunbans
209 (
210 ID INT NOT NULL AUTO_INCREMENT,
211 userID VARCHAR(25),
212 guildID VARCHAR(25) NOT NULL,
213 actioner VARCHAR(25),
214 description text,
215 identifier VARCHAR(10),
216 isDeleted BIT,
217 timestamp DATETIME,
218 updated DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
219 PRIMARY KEY (ID)
220 )
221 CHARACTER SET 'utf8mb4'
222 COLLATE 'utf8mb4_0900_ai_ci';`,
223 function (err, results) {
224 if (err => {
225 throw err;
226 });
227 }
228 );
229 connection.query(
230 `CREATE TABLE IF NOT EXISTS log_note
231 (
232 ID INT NOT NULL AUTO_INCREMENT,
233 userID VARCHAR(25),
234 guildID VARCHAR(25) NOT NULL,
235 actioner VARCHAR(25),
236 description TEXT,
237 identifier VARCHAR(10),
238 isDeleted BIT,
239 timestamp DATETIME NOT NULL,
240 updated DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
241 PRIMARY KEY (id)
242 )
243 CHARACTER SET 'utf8mb4'
244 COLLATE 'utf8mb4_0900_ai_ci';`,
245 function (err, results) {
246 if (err => {
247 throw err;
248 });
249 }
250 );
251 connection.query(
252 `CREATE TABLE IF NOT EXISTS log_warn
253 (
254 ID INT NOT NULL AUTO_INCREMENT,
255 userID VARCHAR(25),
256 guildID VARCHAR(25) NOT NULL,
257 actioner VARCHAR(25),
258 description TEXT,
259 identifier VARCHAR(10),
260 isDeleted BIT,
261 timestamp DATETIME,
262 updated DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
263 PRIMARY KEY (id)
264 )
265 CHARACTER SET 'utf8mb4'
266 COLLATE 'utf8mb4_0900_ai_ci';`,
267 function (err, results) {
268 if (err => {
269 throw err;
270 });
271 }
272 );
273 connection.query(
274 `CREATE TABLE IF NOT EXISTS log_outgoingdm
275 (
276 id int NOT NULL AUTO_INCREMENT,
277 userID VARCHAR(25) NOT NULL,
278 guildID VARCHAR(25) NOT NULL,
279 content text,
280 type TINYINT,
281 isDeleted bit,
282 identifier VARCHAR(10),
283 timestamp DATETIME NOT NULL,
284 updated timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
285 PRIMARY KEY (id)
286 )
287 CHARACTER SET 'utf8mb4'
288 COLLATE 'utf8mb4_0900_ai_ci';`,
289 function (err, results) {
290 if (err => {
291 throw err;
292 });
293 }
294 );
295 connection.query(
296 `CREATE TABLE IF NOT EXISTS log_mutes
297 (
298 ID INT NOT NULL AUTO_INCREMENT,
299 userID VARCHAR(25),
300 guildID VARCHAR(25) NOT NULL,
301 actioner VARCHAR(25),
302 description TEXT,
303 length MEDIUMINT,
304 identifier VARCHAR(10),
305 isDeleted BIT,
306 timestamp DATETIME,
307 updated DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
308 PRIMARY KEY (id)
309 )
310 CHARACTER SET 'utf8mb4'
311 COLLATE 'utf8mb4_0900_ai_ci';`,
312 function (err, results) {
313 if (err => {
314 throw err;
315 });
316 }
317 );
318 connection.query(
319 `INSERT IGNORE INTO messageTypes (id, type) VALUES (1, "create"), (2, "edit"), (3, "delete")`,
320 function (err, results) {
321 if (err => {
322 throw err;
323 });
324 }
325 );
326 connection.query(
327 `INSERT IGNORE INTO voiceTypes (id, type) VALUES (1, "join"), (2, "move"), (3, "leave")`,
328 function (err, results) {
329 if (err => {
330 throw err;
331 });
332 }
333 );
334}
335
336function parseUserTag(tag) {
337 var trimMe = tag.trim();
338
339 if (/(<@(!)*)+\w+(>)/.test(tag)) {
340 return trimMe.replace(/[^0-9.]/gi, ``);
341 } else if (/[\w\d\\\/\_\|]+(#\d\d\d\d)+$/.test(tag)) {
342 var split = tag.split(`#`);
343 var usernameResolve = client.users.find(obj => obj.username === split[0]);
344
345 if (usernameResolve.discriminator == split[1]) {
346 return usernameResolve.id;
347 } else {
348 return `err`;
349 }
350 } else if (/^[0-9]+$/.test(tag)) {
351 return trimMe;
352 } else {
353 var usernameResolve = client.users.find(obj => obj.username === tag);
354 var nicknameResolve = client.users.find(obj => obj.nickname === tag);
355
356 if (usernameResolve) {
357 return usernameResolve.id;
358 } else if (nicknameResolve) {
359 return nicknameResolve.id;
360 } else {
361 return `user not found`;
362 }
363 }
364}
365
366function updateUserTable(invoker, channel, guild) {
367 var memberArray = [];
368
369 client.guilds.get(guild).fetchMembers().then(r => {
370 r.members.array().forEach(r => {
371 memberArray.push([r.user.id, r.guild.id, r.user.username, r.user.avatar, 1, r.joinedAt]);
372 });
373 connection.query(
374 `INSERT IGNORE INTO users (userID, guildID, username, avatar, exist, timestamp) VALUES ?`, [memberArray],
375 function (err, results) {
376 if (err => {
377 throw err;
378 });
379 if (results) {
380 switch (invoker) {
381 case "user":
382 const updateUserTableEmbed = new Discord.RichEmbed()
383 .setColor(locale.info_color)
384 .setAuthor(locale.bot_name, locale.bot_avatar_link)
385 .setTitle(`**User update**`)
386 .setDescription(`Users that are not in the database will be inserted`)
387 .addField(`Total users found`, memberArray.length, true)
388 .addField(`Total users inserted`, results.affectedRows, true)
389 .setTimestamp()
390 .setFooter(`Gab's Child | Version: ${config.version}`)
391 if (channel === undefined) return;
392 client.channels.get(channel).send(updateUserTableEmbed);
393 }
394 }
395 }
396 );
397 })
398}
399
400function updateGuildBansTable(invoker, channel) {
401 var banArray = [];
402 var guild = message.guild;
403
404 guild.fetchBans().then(bans => {
405 bans.array().forEach(ban => {
406 banArray.push([ban.id, ban.username, ban.discriminator, `001`, null, `Ban inserted via a call to updateGuildBansTable`, new Date()]);
407 });
408 connection.query(
409 `INSERT IGNORE INTO log_guildbans (userID, username, discriminator, bannedBy, reason, note, timestamp) VALUES ?`, [banArray],
410 function (results) {
411 switch (invoker) {
412 case `user`:
413 const updateGuildBansTableEmbed = new Discord.RichEmbed()
414 .setColor(locale.info_color)
415 .setAuthor(locale.bot_name, locale.bot_avatar_link)
416 .setTitle(`**Bans update**`)
417 .setDescription(`Bans that are not in the database will be inserted`)
418 .addField(`Total bans found`, bans.size, true)
419 .addField(`Total bans inserted`, results.affectedRows, true)
420 .setTimestamp()
421 .setFooter(`Gab's Child | Version: ${config.version}`);
422
423 client.channels.get(channel).send(updateGuildBansTableEmbed);
424 }
425 }
426 );
427 })
428}
429
430function checkExpiredMutes() {
431 var gKeys = _.keys(channelsFile.read());
432 for (var i = 0; i < gKeys.length; i++) {
433 var guild = client.guilds.get(gKeys[i]);
434 var mutes = mutedFile.read();
435 var muteKeys = _.keys(mutes);
436
437 for (var a = 0; a < muteKeys.length; a++) {
438 let key = muteKeys[a];
439 if (mutes[key].end < Math.floor(Date.now() / 1000 && mutes[key].guild == guild.id)) {
440 var actionee = guild.member(key);
441 var mutedRole = guild.roles.find(val => val.id === config.muted_role);
442
443 if (actionee) {
444 actionee.removeRole(mutedRole)
445 .then(member => {
446 guild.channels.find(val => val.id === config.server_log).send(updateGuildBansTableEmbed = new Discord.RichEmbed()
447 .setColor(locale.info_color)
448 .setAuthor(locale.bot_name, locale.bot_avatar_link)
449 .setTitle(`**Mute expired**`)
450 .setDescription(`Mute of user ${member} has expired`)
451 .setTimestamp()
452 .setFooter(`Gab's Child | Version: ${config.version}`));
453
454 mutedFile.unset(key);
455 mutedFile.save();
456 })
457 .catch(console.error);
458 } else {
459 console.log(`Actionee could not be found ${key}`);
460 mutedFile.unset(key);
461 mutedFile.save();
462 }
463 }
464 }
465 }
466}
467
468function checkMessageContent(message) {
469 var wholeMessage = (message.content.toLowerCase()).split(` `);
470 var allowedKeys = _.keys(allowedRolesFile.read());
471 if(!allowedKeys.some(guildId => [message.guild.id].includes(guildId))) return;
472 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
473 if(!allowedRoles.length > 0) return;
474 if(!_.keys(badWordsFile.read()).some(guildId => [message.guild.id].includes(guildId))) return;
475 var badWordsList = badWordsFile.get(message.guild.id).badwords;
476 if(!badWordsList.length > 0) return;
477 if (!message.member.roles.some(role => allowedRoles.includes(role.id))) {
478 if (badWordsList.some(word => wholeMessage.includes(word))) {
479 message.delete();
480 deletedByBot = 1;
481 }
482 } else {
483 return;
484 }
485}
486
487// Bot Ready Listener Event
488client.on(`ready`, () => {
489 console.log(`Bot has started and logged in.`);
490
491 setupTables();
492
493 var gKeys = _.keys(channelsFile.read());
494 var i = 0;
495
496 function loop() {
497 setTimeout(function () {
498 var guild = gKeys[i];
499 updateUserTable(`user`, channelsFile.get(guild).bot_log, guild);
500 //updateGuildBansTable(`user`, channelsFile.get(guild).bot_log);
501 i++;
502 if (i < gKeys.length) loop();
503 }, 100)
504 }
505 loop();
506
507 setInterval(checkExpiredMutes, 10000);
508
509});
510
511// Message Received Listener Event
512client.on(`message`, async message => {
513 if (message.author.bot) return;
514 if (_.indexOf(["dm", "group"], message.channel.type) !== -1) return;
515
516 if(!_.keys(allowedRolesFile.read()).some(guildId => [message.guild.id].includes(guildId))) {
517 allowedRolesFile.set(`${message.guild.id}.allowedRoles`, []);
518 }
519
520 checkMessageContent(message);
521
522 if (message.content.indexOf(config.prefix) !== 0) return;
523
524 const args = message.content.slice(config.prefix.length).split(/ +/);
525 const command = args.shift().toLowerCase();
526
527 if(!((allowedRolesFile.get(message.guild.id).allowedRoles).length > 0) && message.content.indexOf(config.prefix) == 0 && (!(command === `help`) && (!(command ===`status`)))) {
528 message.channel.send(`Please have the guild owner set up allowed roles with \`${config.prefix}bot role add <role_id>\``);
529 }
530
531 // Help command
532 if (command === `help`) {
533 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
534 if (!message.member.roles.some(role => allowedRoles.includes(role.id))) {
535 const helpEmbed = new Discord.RichEmbed()
536 .setColor(locale.info_color)
537 .setAuthor(locale.bot_name, locale.bot_avatar_link)
538 .setTitle(`**Listing all commands**`)
539 .setDescription(`**General Commands**\n
540 \`${config.prefix}help\` - lists all commands\n
541 \`${config.prefix}status\` - shows bot's status`)
542 .setTimestamp()
543 .setFooter(`Gab's Child | Version: ${config.version}`);
544 message.channel.send(helpEmbed);
545 } else if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
546 const adminHelpEmbed = new Discord.RichEmbed()
547 .setColor(locale.info_color)
548 .setAuthor(locale.bot_name, locale.bot_avatar_link)
549 .setTitle(`**Listing all commands**`)
550 .setDescription(`**General Commands**
551 \`${config.prefix}help\` - lists all commands
552 \`${config.prefix}status\` - shows bot's status
553 \n**Admin Commands**\n
554 \`${config.prefix}channels set <server_log/bot_log>\` - sets a channel as server log or bot log
555 \`${config.prefix}badwords list\` - lists all bad words
556 \`${config.prefix}badwords add <words>\` - adds bad words
557 \`${config.prefix}badwords remove <words>\` - removes bad words
558 \`${config.prefix}badwords clear\` - clears all bad words
559 \`${config.prefix}user <user>\` - shows information of a user
560 \`${config.prefix}users count\` - shows how many users are inserted into database
561 \`${config.prefix}users update\` - inserts all users into database
562 \`${config.prefix}ban <user> <reason>\` - bans a user
563 \`${config.prefix}unban <user> <reason>\` - unbans a user
564 \`${config.prefix}warn <user> <reason>\` - warns a user
565 \`${config.prefix}cwarn <identifier>\` - removes a warning
566 \`${config.prefix}mute <user> <duration> <reason>\` - mutes a user
567 \`${config.prefix}disconnect <user>\` - disconnects a user from their voice channel
568 \`${config.prefix}note <user> <reason>\` - adds a note to a user
569 \`${config.prefix}cnote <identifier>\` - removes a note
570 \`${config.prefix}voicelog <user>\` - shows a user's voice log`)
571 .setTimestamp()
572 .setFooter(`Gab's Child | Version: ${config.version}`);
573
574 message.channel.send(adminHelpEmbed);
575 }
576 }
577
578 // Ping command
579 if (command === `status`) {
580 var client_ping = Math.floor(client.ping);
581 var db_ping = connection.ping();
582
583 var client_status;
584 var db_status;
585
586 if (client_ping >= 1 && client_ping <= 500) {
587 client_status = `OK`;
588 } else if (client_ping > 500 && client_ping <= 5000) {
589 client_status = `Degraded`;
590 } else {
591 client_status = `Severely degraded or error`;
592 }
593
594 if (db_ping) {
595 db_status = `OK`;
596 } else {
597 db_status = `Severely degraded or error`;
598 }
599
600 message.channel.send(new Discord.RichEmbed()
601 .setColor(locale.info_color)
602 .setAuthor(locale.bot_name, locale.bot_avatar_link)
603 .setTitle(`**Bot status**`)
604 .addField(`Client`, `${client_status} (${client_ping}ms)`, true)
605 .addField(`Database`, `${db_status}`, true)
606 .setTimestamp()
607 .setFooter(`Gab's Child | Version: ${config.version}`));
608 }
609
610 // Ban command
611 if (command === `ban`) {
612 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
613 if (!message.member.roles.some(role => allowedRoles.includes(role.id))) {
614 return;
615 } else if (!args[0]) {
616 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
617 } else if (args[0]) {
618 var user = parseUserTag(args[0]);
619 var guild = message.guild;
620
621 if (user == `err`) {
622 message.channel.send(`:x: Could not find user ${user}.`);
623 } else {
624 if (guild.member(user)) {
625 if (message.member.highestRole.comparePositionTo(guild.member(user).highestRole) > 0) {
626 var tail = args.slice(1);
627 var reason = tail.join(` `).trim();
628
629 if (tail.length > 0) {
630 var identifier = cryptoRandomString({
631 length: 10
632 });
633
634 client.users.get(user).createDM().then(async chnl => {
635 const userBannedDMEmbed = new Discord.RichEmbed()
636 .setColor(locale.bad_color)
637 .setAuthor(locale.bot_name, locale.bot_avatar_link)
638 .setTitle(`**You have been banned from ${guild.name}**`)
639 .setDescription(`Details about the ban:`)
640 .addField(`Ban reason`, `${reason}`, false)
641 .addField(`Identifier`, `${identifier}`, false)
642 .setTimestamp()
643 .setFooter(`Gab's Child | Version: ${config.version}`)
644 chnl.send(userBannedDMEmbed).then(dm => {
645 var data = [user, message.guild.id, `Title: ${dm.embeds[0].title}`, 2, 0, identifier, new Date(), new Date()];
646 connection.query(`INSERT INTO log_outgoingdm(userid, guildId, content, type, isDeleted, identifier, timestamp, updated) VALUES(?,?,?,?,?,?,?,?)`, data)
647 });
648
649 guild.ban(user, {
650 days: 1,
651 reason: reason
652 }).then(async result => {
653 const userBannedEmbed = new Discord.RichEmbed()
654 .setColor(locale.good_color)
655 .setAuthor(result.username, result.avatarURL)
656 .setTitle(`**User banned**`)
657 .setDescription(`${client.users.get(user)} has been successfully banned`)
658 .addField(`User ID`, `${result.id}`, true)
659 .addField(`Username`, `${result.username}#${result.discriminator}`, true)
660 .addField(`Reason`, `${reason}`, false)
661 .addField(`Banned by`, `${message.author}`, false)
662 .addField(`Identifier`, `${identifier}`, false)
663 .setTimestamp()
664 .setFooter(`Gab's Child | Version: ${config.version}`)
665
666 message.channel.send(userBannedEmbed);
667
668 var data = [result.id, guild.id, message.author.id, reason, identifier, 0, new Date()];
669 connection.query(
670 `INSERT INTO log_guildbans (userID, guildID, actioner, description, identifier, isDeleted, timestamp) VALUES (?,?,?,?,?,?,?)`, data,
671 function (err, results) {
672 if (err => {
673 throw err;
674 });
675 })
676
677 bannedUsersFile.set(identifier, result.username);
678 bannedUsersFile.save();
679
680 });
681 });
682 } else {
683 message.channel.send(`:x: Please provide a reason for the ban.`)
684 }
685 } else {
686 message.channel.send(`:x: You cannot ban a user with a higher role than yourself.`);
687 }
688 } else {
689 message.channel.send(`:x: The specified user was not found.`)
690 }
691 }
692 } else if (!message.member.roles.some(role => ["Admin"].includes(role.name))) {
693 return;
694 }
695 }
696
697 // Unban command
698 if (command === `unban`) {
699 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
700 if (!message.member.roles.some(role => allowedRoles.includes(role.id))) {
701 return;
702 } else if (!args[0]) {
703 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
704 } else if (args[0]) {
705 var user = parseUserTag(args[0]);
706 var guild = message.guild;
707
708 if (user == `err`) {
709 message.channel.send(`:x: Could not find user ${user}.`);
710 } else {
711 if (client.fetchUser(user)) {
712 var tail = args.slice(1);
713 var reason = tail.join(` `).trim();
714
715 if (tail.length > 0) {
716 guild.unban(user, reason).then(result => {
717 var identifier = cryptoRandomString({
718 length: 10
719 });
720 const userUnbannedEmbed = new Discord.RichEmbed()
721 .setColor(locale.good_color)
722 .setAuthor(result.username, result.avatarURL)
723 .setTitle(`**User unbanned**`)
724 .setDescription(`${client.users.get(user)} has been successfully unbanned`)
725 .addField(`User ID`, `${result.id}`, true)
726 .addField(`Username`, `${result.username}#${result.discriminator}`, true)
727 .addField(`Reason`, `${reason}`, false)
728 .addField(`Unbanned by`, `${message.author}`, false)
729 .addField(`Identifier`, `${identifier}`, false)
730 .setTimestamp()
731 .setFooter(`Gab's Child | Version: ${config.version}`)
732
733 message.channel.send(userUnbannedEmbed);
734
735 var data = [result.id, guild.id, message.author.id, reason, identifier, 0, new Date()];
736 connection.query(
737 `INSERT INTO log_guildunbans (userID, guildID, actioner, description, identifier, isDeleted, timestamp) VALUES (?,?,?,?,?,?,?)`, data,
738 function (err, results) {
739 if (err => {
740 throw err;
741 });
742 });
743 var dataTwo = [result.id, guild.id];
744 connection.query(`
745 SELECT identifier FROM log_guildbans WHERE userID = ? AND guildID = ? ORDER BY timestamp DESC LIMIT 1`, dataTwo);
746
747 bannedUsersFile.set(identifier, result.username);
748 bannedUsersFile.save();
749
750 }).catch(err => {
751 if (err.message === `Unknown Ban`) {
752 message.channel.send(`:x: The specified user is not banned!`);
753 } else {
754 console.log(err);
755 }
756 });
757 } else {
758 message.channel.send(`:x: Please provide a reason for the unban.`)
759 }
760 } else {
761 message.channel.send(`:x: The specified user was not found.`)
762 }
763 }
764 } else if (!message.member.roles.some(role => ["Admin"].includes(role.name))) {
765 return;
766 }
767 }
768
769 // User command
770 if (command === `user`) {
771 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
772 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
773 if (!args[0]) {
774 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
775 return;
776 }
777 var userID = parseUserTag(args[0]);
778 var globalUser = client.users.get(userID);
779 var guild = message.guild;
780 var userObject = guild.member(globalUser);
781
782 if (userObject) {
783 var nickname;
784 var voiceChannel;
785 var game;
786
787 if (userObject.displayName && userObject.user.username != userObject.displayName) {
788 nickname = userObject.displayName
789 } else {
790 nickname = "No nickname"
791 };
792 if (userObject.voiceChannel) {
793 voiceChannel = userObject.voiceChannel.name
794 } else {
795 voiceChannel = "Not in voice channel"
796 };
797 if (userObject.presence.game) {
798 game = userObject.presence.game.name
799 } else {
800 game = "None"
801 };
802
803 const userEmbed = new Discord.RichEmbed()
804 .setColor(locale.info_color)
805 .setAuthor(`Information of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
806 .setThumbnail(userObject.user.avatarURL)
807 .setDescription(`${userObject.user} joined ${userObject.guild.name} on ${userObject.joinedAt}`)
808 .addField(`Created`, userObject.user.createdAt, false)
809 .addField(`Status`, `${(userObject.presence.status).toUpperCase()}`, true)
810 .addField(`Game`, game, true)
811 .addField(`Voice channel`, voiceChannel, false)
812 .setTimestamp()
813 .setFooter(`Gab's Child | Version: ${config.version}`);
814
815 message.channel.send(userEmbed).then(async message => {
816 await message.react("?");
817 await message.react("?");
818 await message.react("?");
819 await message.react("✍");
820 await message.react("?");
821 await message.react("❌");
822
823 const filter = (reaction, user) => user.bot == false;
824 const collector = message.createReactionCollector(filter);
825
826 collector.on(`collect`, async r => {
827 if (r.emoji.name == `?`) {
828 await r.remove(r.users.last());
829 message.edit(new Discord.RichEmbed()
830 .setColor(locale.info_color)
831 .setAuthor(`Information of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
832 .setThumbnail(userObject.user.avatarURL)
833 .setDescription(`${userObject.user} joined ${userObject.guild.name} on ${userObject.joinedAt}`)
834 .addField(`Created`, userObject.user.createdAt, false)
835 .addField(`Status`, `${(userObject.presence.status).toUpperCase()}`, true)
836 .addField(`Game`, game, true)
837 .addField(`Voice channel`, voiceChannel, false)
838 .setTimestamp()
839 .setFooter(`Gab's Child | Version: ${config.version}`));
840 } else if (r.emoji.name == `?`) {
841 await r.remove(r.users.last());
842
843 connection.query(`(SELECT 'unban' as \`type\`, gub.* FROM log_guildunbans gub WHERE gub.userid = ${connection.escape(userID)} AND gub.isDeleted = 0 AND gub.guildID = ${connection.escape(guild.id)}
844 UNION ALL SELECT 'ban' as \`type\`, gb.* FROM log_guildbans gb WHERE gb.userid = ${connection.escape(userID)} AND gb.guildID = ${connection.escape(guild.id)} AND gb.isDeleted = 0 AND gb.actioner <> '001' UNION ALL
845 SELECT 'warn' AS \`type\`, w.* FROM log_warn w WHERE w.userid = ${connection.escape(userID)} AND w.isDeleted = 0 AND w.guildID = ${connection.escape(guild.id)}) ORDER BY timestamp DESC`,
846 async function (err, rows, results) {
847 if (err) throw err;
848 var events = [];
849 var max = 5;
850 var extra;
851
852 if (rows.length <= max) {
853 max = rows.length;
854 } else {
855 extra = rows.length - max;
856 }
857
858 for (var i = 0; i < max; i++) {
859 var row = rows[i];
860 if (row.type == `warn`) {
861 await events.push(`\`${row.identifier}\` :exclamation: Warned by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`);
862 } else if (row.type == `ban`) {
863 await events.push(`\`${row.identifier}\` :crossed_swords: Banned by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`);
864 } else if (row.type == `unban`) {
865 await events.push(`\`${row.identifier}\` :shield: Unbanned by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`);
866 }
867 if (i == max - 1 && extra > 0) {
868 events.push(`...${extra} more`);
869 }
870 }
871 if (!_.isEmpty(events)) {
872 await message.edit(new Discord.RichEmbed()
873 .setColor(locale.info_color)
874 .setAuthor(`Infractions of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
875 .setDescription(events.join(`\n`))
876 .setTimestamp()
877 .setFooter(`Gab's Child | Version: ${config.version}`));
878 } else {
879 await message.edit(new Discord.RichEmbed()
880 .setColor(locale.info_color)
881 .setAuthor(`Infractions of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
882 .setDescription(`This user has no infractions`)
883 .setTimestamp()
884 .setFooter(`Gab's Child | Version: ${config.version}`));
885 }
886 })
887 } else if (r.emoji.name == `?`) {
888 await r.remove(r.users.last());
889
890 connection.query(`SELECT * FROM log_mutes WHERE userID = ? AND guildID = ${connection.escape(guild.id)} AND isDeleted = 0 ORDER BY timestamp DESC`, userID, async function (err, rows, results) {
891 if (err) throw err;
892 var mutes = [];
893 var max = 5;
894 var extra;
895
896 if (rows.length <= 5) {
897 max = rows.length;
898 } else {
899 extra = rows.length - max;
900 }
901
902 for (var i = 0; i < max; i++) {
903 var row = rows[i];
904 await mutes.push(`\`${row.identifier}\` :mute: Muted by ${client.users.get(row.actioner)} on ${row.timestamp} for ${row.length}s\n\`\`\`${row.description}\`\`\`\n`)
905 if (i == max - 1 && extra > 0) {
906 mutes.push(`...${extra} more`);
907 }
908 }
909 if (!_.isEmpty(mutes)) {
910 await message.edit(new Discord.RichEmbed()
911 .setColor(locale.info_color)
912 .setAuthor(`Mutes of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
913 .setDescription(mutes.join(" "))
914 .setTimestamp()
915 .setFooter(`Gab's Child | Version: ${config.version}`));
916 } else {
917 await message.edit(new Discord.RichEmbed()
918 .setColor(locale.info_color)
919 .setAuthor(`Mutes of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
920 .setDescription(`This user has no mutes`)
921 .setTimestamp()
922 .setFooter(`Gab's Child | Version: ${config.version}`));
923 }
924 })
925 } else if (r.emoji.name == `✍`) {
926 await r.remove(r.users.last());
927
928 connection.query(`SELECT * FROM log_note WHERE userID = ? AND guildID = ${connection.escape(guild.id)} AND isDeleted = 0 ORDER BY timestamp DESC`, userID, async function (err, rows, results) {
929 if (err) throw err;
930 var notes = [];
931 for (var i = 0; i < rows.length; i++) {
932 var row = rows[i];
933 await notes.push(`\`${row.identifier}\` :pushpin: Note by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`)
934 }
935 if (!_.isEmpty(notes)) {
936 message.edit(new Discord.RichEmbed()
937 .setColor(locale.info_color)
938 .setAuthor(`Notes of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
939 .setDescription(notes.join(" "))
940 .setTimestamp()
941 .setFooter(`Gab's Child | Version: ${config.version}`));
942 } else {
943 message.edit(new Discord.RichEmbed()
944 .setColor(locale.info_color)
945 .setAuthor(`Notes of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
946 .setDescription(`This user has no notes`)
947 .setTimestamp()
948 .setFooter(`Gab's Child | Version: ${config.version}`));
949 }
950 })
951 } else if (r.emoji.name == `?`) {
952 await r.remove(r.users.last());
953 connection.query(`
954 SELECT Status, timestamp FROM(SELECT *, 'join' AS Status from log_guildjoin WHERE userid = ? AND guildID = ${connection.escape(guild.id)}
955 UNION SELECT *, 'leave' AS Status FROM log_guildleave WHERE userid = ? AND guildID = ${connection.escape(guild.id)}) a
956 ORDER BY timestamp DESC`, [userID, userID], async function (err, rows, results) {
957 if (err) throw err;
958 var history = [];
959 var max = 5;
960 var extra;
961
962 if (rows.length <= 5) {
963 max = rows.length;
964 } else {
965 extra = rows.length - max;
966 }
967
968 for (var i = 0; i < max; i++) {
969 var row = rows[i];
970 switch (row.Status) {
971 case `join`:
972 history.push(`:inbox_tray: ${userObject.user.username} joined ${guild.name} at \`\`\`${new Date(row.timestamp)}\`\`\`\n`);
973 break;
974 case `leave`:
975 history.push(`:outbox_tray: ${userObject.user.username} left ${guild.name} at \`\`\`${new Date(row.timestamp)}\`\`\`\n`);
976 break;
977 }
978
979 if (i == max - 1 && extra > 0) {
980 history.push(`...${extra} more`);
981 }
982 }
983
984 if (!_.isEmpty(history)) {
985 await message.edit(new Discord.RichEmbed()
986 .setColor(locale.info_color)
987 .setAuthor(`Join/Leave history of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
988 .setDescription(history.join(" "))
989 .setTimestamp()
990 .setFooter(`Gab's Child | Version: ${config.version}`));
991 } else {
992 await message.edit(new Discord.RichEmbed()
993 .setColor(locale.info_color)
994 .setAuthor(`Notes of ${userObject.user.username} (${nickname})`, userObject.user.avatarURL)
995 .setDescription(`This user has no Join/Leave history`)
996 .setTimestamp()
997 .setFooter(`Gab's Child | Version: ${config.version}`))
998 }
999 })
1000 } else if (r.emoji.name == `❌`) {
1001 message.delete();
1002 }
1003 })
1004
1005 });
1006 } else if (globalUser) {
1007 const userEmbed = new Discord.RichEmbed()
1008 .setColor(locale.info_color)
1009 .setAuthor(`Information of ${globalUser.username}`, globalUser.avatarURL)
1010 .setThumbnail(globalUser.avatarURL)
1011 .setDescription(`The user is not present in this guild`)
1012 .setTimestamp()
1013 .setFooter(`Gab's Child | Version: ${config.version}`);
1014
1015 message.channel.send(userEmbed).then(async message => {
1016 await message.react("?");
1017 await message.react("?");
1018 await message.react("?");
1019 await message.react("✍");
1020 await message.react("?");
1021 await message.react("❌");
1022
1023 const filter = (reaction, user) => user.bot == false;
1024 const collector = message.createReactionCollector(filter);
1025
1026 collector.on(`collect`, async r => {
1027 if (r.emoji.name == `?`) {
1028 await r.remove(r.users.last());
1029 message.edit(new Discord.RichEmbed()
1030 .setColor(locale.info_color)
1031 .setAuthor(`Information of ${globalUser.username}`, globalUser.avatarURL)
1032 .setThumbnail(globalUser.avatarURL)
1033 .setDescription(`The user is not present in this guild`)
1034 .setTimestamp()
1035 .setFooter(`Gab's Child | Version: ${config.version}`));
1036 } else if (r.emoji.name == `?`) {
1037 await r.remove(r.users.last());
1038
1039 connection.query(`(SELECT 'unban' as \`type\`, gub.* FROM log_guildunbans gub WHERE gub.userid = ${connection.escape(userID)} AND gub.isDeleted = 0 AND gub.guildID = ${connection.escape(guild.id)}
1040 UNION ALL SELECT 'ban' as \`type\`, gb.* FROM log_guildbans gb WHERE gb.userid = ${connection.escape(userID)} AND gb.isDeleted = 0 AND gb.actioner AND gb.guildID = ${connection.escape(guild.id)} <> '001' UNION ALL
1041 SELECT 'warn' AS \`type\`, w.* FROM log_warn w WHERE w.userid = ${connection.escape(userID)} AND w.isDeleted = 0 AND w.guildID = ${connection.escape(guild.id)}) ORDER BY timestamp DESC`,
1042 async function (err, rows, results) {
1043 if (err) throw err;
1044 var events = [];
1045 var max = 5;
1046 var extra;
1047
1048 if (rows.length <= max) {
1049 max = rows.length;
1050 } else {
1051 extra = rows.length - max;
1052 }
1053
1054 for (var i = 0; i < max; i++) {
1055 var row = rows[i];
1056 if (row.type == `warn`) {
1057 await events.push(`\`${row.identifier}\` :exclamation: Warned by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`);
1058 } else if (row.type == `ban`) {
1059 await events.push(`\`${row.identifier}\` :crossed_swords: Banned by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`);
1060 } else if (row.type == `unban`) {
1061 await events.push(`\`${row.identifier}\` :shield: Unbanned by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`);
1062 }
1063 if (i == max - 1 && extra > 0) {
1064 events.push(`...${extra} more`);
1065 }
1066 }
1067 if (!_.isEmpty(events)) {
1068 await message.edit(new Discord.RichEmbed()
1069 .setColor(locale.info_color)
1070 .setAuthor(`Infractions of ${globalUser.username}`, globalUser.avatarURL)
1071 .setDescription(events.join(`\n`))
1072 .setTimestamp()
1073 .setFooter(`Gab's Child | Version: ${config.version}`));
1074 } else {
1075 await message.edit(new Discord.RichEmbed()
1076 .setColor(locale.info_color)
1077 .setAuthor(`Infractions of ${globalUser.username}`, globalUser.avatarURL)
1078 .setDescription(`This user has no infractions`)
1079 .setTimestamp()
1080 .setFooter(`Gab's Child | Version: ${config.version}`));
1081 }
1082 })
1083 } else if (r.emoji.name == `?`) {
1084 await r.remove(r.users.last());
1085
1086 connection.query(`SELECT * FROM log_mutes WHERE userID = ? AND guildID = ${connection.escape(guild.id)} AND isDeleted = 0 ORDER BY timestamp DESC`, userID, async function (err, rows, results) {
1087 if (err) throw err;
1088 var mutes = [];
1089 var max = 5;
1090 var extra;
1091
1092 if (rows.length <= 5) {
1093 max = rows.length;
1094 } else {
1095 extra = rows.length - max;
1096 }
1097
1098 for (var i = 0; i < max; i++) {
1099 var row = rows[i];
1100 await mutes.push(`\`${row.identifier}\` :mute: Muted by ${client.users.get(row.actioner)} on ${row.timestamp} for ${row.length}s\n\`\`\`${row.description}\`\`\`\n`)
1101 if (i == max - 1 && extra > 0) {
1102 mutes.push(`...${extra} more`);
1103 }
1104 }
1105 if (!_.isEmpty(mutes)) {
1106 await message.edit(new Discord.RichEmbed()
1107 .setColor(locale.info_color)
1108 .setAuthor(`Mutes of ${globalUser.username}`, globalUser.avatarURL)
1109 .setDescription(mutes.join(" "))
1110 .setTimestamp()
1111 .setFooter(`Gab's Child | Version: ${config.version}`));
1112 } else {
1113 await message.edit(new Discord.RichEmbed()
1114 .setColor(locale.info_color)
1115 .setAuthor(`Mutes of ${globalUser.username}`, globalUser.avatarURL)
1116 .setDescription(`This user has no mutes`)
1117 .setTimestamp()
1118 .setFooter(`Gab's Child | Version: ${config.version}`));
1119 }
1120 })
1121 } else if (r.emoji.name == `✍`) {
1122 await r.remove(r.users.last());
1123
1124 connection.query(`SELECT * FROM log_note WHERE userID = ? AND guildID = ${connection.escape(guild.id)} AND isDeleted = 0 ORDER BY timestamp DESC`, userID, async function (err, rows, results) {
1125 if (err) throw err;
1126 var notes = [];
1127 for (var i = 0; i < rows.length; i++) {
1128 var row = rows[i];
1129 await notes.push(`\`${row.identifier}\` :pushpin: Note by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`)
1130 }
1131 if (!_.isEmpty(notes)) {
1132 message.edit(new Discord.RichEmbed()
1133 .setColor(locale.info_color)
1134 .setAuthor(`Notes of ${globalUser.username}`, globalUser.avatarURL)
1135 .setDescription(notes.join(" "))
1136 .setTimestamp()
1137 .setFooter(`Gab's Child | Version: ${config.version}`));
1138 } else {
1139 message.edit(new Discord.RichEmbed()
1140 .setColor(locale.info_color)
1141 .setAuthor(`Notes of ${globalUser.username}`, globalUser.avatarURL)
1142 .setDescription(`This user has no notes`)
1143 .setTimestamp()
1144 .setFooter(`Gab's Child | Version: ${config.version}`));
1145 }
1146 })
1147 } else if (r.emoji.name == `?`) {
1148 await r.remove(r.users.last());
1149 connection.query(`
1150 SELECT Status, timestamp FROM(SELECT *, 'join' AS Status from log_guildjoin WHERE userid = ? AND guildID = ${connection.escape(guild.id)}
1151 UNION SELECT *, 'leave' AS Status FROM log_guildleave WHERE userid = ? AND guildID = ${connection.escape(guild.id)}) a
1152 ORDER BY timestamp DESC`, [userID, userID], async function (err, rows, results) {
1153 if (err) throw err;
1154 var history = [];
1155 var max = 5;
1156 var extra;
1157
1158 if (rows.length <= 5) {
1159 max = rows.length;
1160 } else {
1161 extra = rows.length - max;
1162 }
1163
1164 for (var i = 0; i < max; i++) {
1165 var row = rows[i];
1166 switch (row.Status) {
1167 case `join`:
1168 history.push(`:inbox_tray: ${globalUser.username} joined ${guild.name} at \`\`\`${new Date(row.timestamp)}\`\`\`\n`);
1169 break;
1170 case `leave`:
1171 history.push(`:outbox_tray: ${globalUser.username} left ${guild.name} at \`\`\`${new Date(row.timestamp)}\`\`\`\n`);
1172 break;
1173 }
1174
1175 if (i == max - 1 && extra > 0) {
1176 history.push(`...${extra} more`);
1177 }
1178 }
1179
1180 if (!_.isEmpty(history)) {
1181 await message.edit(new Discord.RichEmbed()
1182 .setColor(locale.info_color)
1183 .setAuthor(`Join/Leave history of ${globalUser.username}`, globalUser.avatarURL)
1184 .setDescription(history.join(" "))
1185 .setTimestamp()
1186 .setFooter(`Gab's Child | Version: ${config.version}`));
1187 } else {
1188 await message.edit(new Discord.RichEmbed()
1189 .setColor(locale.info_color)
1190 .setAuthor(`Notes of ${globalUser.username}`, globalUser.avatarURL)
1191 .setDescription(`This user has no Join/Leave history`)
1192 .setTimestamp()
1193 .setFooter(`Gab's Child | Version: ${config.version}`))
1194 }
1195 })
1196 } else if (r.emoji.name == `❌`) {
1197 message.delete();
1198 }
1199 })
1200 });
1201 } else {
1202 connection.query(`SELECT * FROM users WHERE userid = ? AND guildID = ${connection.escape(guild.id)} ORDER BY updated DESC LIMIT 1`, userID, async function (err, rows, results) {
1203 var cardUser = rows[0];
1204 const userEmbed = new Discord.RichEmbed()
1205 .setColor(locale.info_color)
1206 .setAuthor(`Information of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1207 .setThumbnail(`https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1208 .setDescription(`The user could not be resolved, all data will be taken from the database`)
1209 .setTimestamp()
1210 .setFooter(`Gab's Child | Version: ${config.version}`);
1211
1212 message.channel.send(userEmbed).then(async message => {
1213 await message.react("?");
1214 await message.react("?");
1215 await message.react("?");
1216 await message.react("✍");
1217 await message.react("?");
1218 await message.react("❌");
1219
1220 const filter = (reaction, user) => user.bot == false;
1221 const collector = message.createReactionCollector(filter);
1222
1223 collector.on(`collect`, async r => {
1224 if (r.emoji.name == `?`) {
1225 await r.remove(r.users.last());
1226 message.edit(new Discord.RichEmbed()
1227 .setColor(locale.info_color)
1228 .setAuthor(`Information of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1229 .setThumbnail(`https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1230 .setDescription(`The user could not be resolved, all data will be taken from the database`)
1231 .setTimestamp()
1232 .setFooter(`Gab's Child | Version: ${config.version}`));
1233 } else if (r.emoji.name == `?`) {
1234 await r.remove(r.users.last());
1235
1236 connection.query(`(SELECT 'unban' as \`type\`, gub.* FROM log_guildunbans gub WHERE gub.userid = ${connection.escape(userID)} AND gub.isDeleted = 0 AND gub.guildID = ${connection.escape(guild.id)}
1237 UNION ALL SELECT 'ban' as \`type\`, gb.* FROM log_guildbans gb WHERE gb.userid = ${connection.escape(userID)} AND gb.isDeleted = 0 AND gb.actioner AND gb.guildID = ${connection.escape(guild.id)} <> '001' UNION ALL
1238 SELECT 'warn' AS \`type\`, w.* FROM log_warn w WHERE w.userid = ${connection.escape(userID)} AND w.isDeleted = 0 AND w.guildID = ${connection.escape(guild.id)}) ORDER BY timestamp DESC`,
1239 async function (err, rows, results) {
1240 if (err) throw err;
1241 var events = [];
1242 var max = 5;
1243 var extra;
1244
1245 if (rows.length <= max) {
1246 max = rows.length;
1247 } else {
1248 extra = rows.length - max;
1249 }
1250
1251 for (var i = 0; i < max; i++) {
1252 var row = rows[i];
1253 if (row.type == `warn`) {
1254 await events.push(`\`${row.identifier}\` :exclamation: Warned by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`);
1255 } else if (row.type == `ban`) {
1256 await events.push(`\`${row.identifier}\` :crossed_swords: Banned by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`);
1257 } else if (row.type == `unban`) {
1258 await events.push(`\`${row.identifier}\` :shield: Unbanned by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`);
1259 }
1260 if (i == max - 1 && extra > 0) {
1261 events.push(`...${extra} more`);
1262 }
1263 }
1264 if (!_.isEmpty(events)) {
1265 await message.edit(new Discord.RichEmbed()
1266 .setColor(locale.info_color)
1267 .setAuthor(`Infractions of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1268 .setDescription(events.join(`\n`))
1269 .setTimestamp()
1270 .setFooter(`Gab's Child | Version: ${config.version}`));
1271 } else {
1272 await message.edit(new Discord.RichEmbed()
1273 .setColor(locale.info_color)
1274 .setAuthor(`Infractions of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1275 .setDescription(`This user has no infractions`)
1276 .setTimestamp()
1277 .setFooter(`Gab's Child | Version: ${config.version}`));
1278 }
1279 })
1280 } else if (r.emoji.name == `?`) {
1281 await r.remove(r.users.last());
1282
1283 connection.query(`SELECT * FROM log_mutes WHERE userID = ? AND guildID = ${connection.escape(guild.id)} AND isDeleted = 0 ORDER BY timestamp DESC`, userID, async function (err, rows, results) {
1284 if (err) throw err;
1285 var mutes = [];
1286 var max = 5;
1287 var extra;
1288
1289 if (rows.length <= 5) {
1290 max = rows.length;
1291 } else {
1292 extra = rows.length - max;
1293 }
1294
1295 for (var i = 0; i < max; i++) {
1296 var row = rows[i];
1297 await mutes.push(`\`${row.identifier}\` :mute: Muted by ${client.users.get(row.actioner)} on ${row.timestamp} for ${row.length}s\n\`\`\`${row.description}\`\`\`\n`)
1298 if (i == max - 1 && extra > 0) {
1299 mutes.push(`...${extra} more`);
1300 }
1301 }
1302 if (!_.isEmpty(mutes)) {
1303 await message.edit(new Discord.RichEmbed()
1304 .setColor(locale.info_color)
1305 .setAuthor(`Mutes of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1306 .setDescription(mutes.join(" "))
1307 .setTimestamp()
1308 .setFooter(`Gab's Child | Version: ${config.version}`));
1309 } else {
1310 await message.edit(new Discord.RichEmbed()
1311 .setColor(locale.info_color)
1312 .setAuthor(`Mutes of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1313 .setDescription(`This user has no mutes`)
1314 .setTimestamp()
1315 .setFooter(`Gab's Child | Version: ${config.version}`));
1316 }
1317 })
1318 } else if (r.emoji.name == `✍`) {
1319 await r.remove(r.users.last());
1320
1321 connection.query(`SELECT * FROM log_note WHERE userID = ? AND guildID = ${connection.escape(guild.id)} AND isDeleted = 0 ORDER BY timestamp DESC`, userID, async function (err, rows, results) {
1322 if (err) throw err;
1323 var notes = [];
1324 for (var i = 0; i < rows.length; i++) {
1325 var row = rows[i];
1326 await notes.push(`\`${row.identifier}\` :pushpin: Note by ${client.users.get(row.actioner)} on ${row.timestamp}\n\`\`\`${row.description}\`\`\`\n`)
1327 }
1328 if (!_.isEmpty(notes)) {
1329 message.edit(new Discord.RichEmbed()
1330 .setColor(locale.info_color)
1331 .setAuthor(`Notes of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1332 .setDescription(notes.join(" "))
1333 .setTimestamp()
1334 .setFooter(`Gab's Child | Version: ${config.version}`));
1335 } else {
1336 message.edit(new Discord.RichEmbed()
1337 .setColor(locale.info_color)
1338 .setAuthor(`Notes of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1339 .setDescription(`This user has no notes`)
1340 .setTimestamp()
1341 .setFooter(`Gab's Child | Version: ${config.version}`));
1342 }
1343 })
1344 } else if (r.emoji.name == `?`) {
1345 await r.remove(r.users.last());
1346 connection.query(`
1347 SELECT Status, timestamp FROM(SELECT *, 'join' AS Status from log_guildjoin WHERE userid = ? AND guildID = ${connection.escape(guild.id)}
1348 UNION SELECT *, 'leave' AS Status FROM log_guildleave WHERE userid = ? AND guildID = ${connection.escape(guild.id)}) a
1349 ORDER BY timestamp DESC`, [userID, userID], async function (err, rows, results) {
1350 if (err) throw err;
1351 var history = [];
1352 var max = 5;
1353 var extra;
1354
1355 if (rows.length <= 5) {
1356 max = rows.length;
1357 } else {
1358 extra = rows.length - max;
1359 }
1360
1361 for (var i = 0; i < max; i++) {
1362 var row = rows[i];
1363 switch (row.Status) {
1364 case `join`:
1365 history.push(`:inbox_tray: ${cardUser.username} joined ${guild.name} at \`\`\`${new Date(row.timestamp)}\`\`\`\n`);
1366 break;
1367 case `leave`:
1368 history.push(`:outbox_tray: ${cardUser.username} left ${guild.name} at \`\`\`${new Date(row.timestamp)}\`\`\`\n`);
1369 break;
1370 }
1371
1372 if (i == max - 1 && extra > 0) {
1373 history.push(`...${extra} more`);
1374 }
1375 }
1376
1377 if (!_.isEmpty(history)) {
1378 await message.edit(new Discord.RichEmbed()
1379 .setColor(locale.info_color)
1380 .setAuthor(`Join/Leave history of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1381 .setDescription(history.join(" "))
1382 .setTimestamp()
1383 .setFooter(`Gab's Child | Version: ${config.version}`));
1384 } else {
1385 await message.edit(new Discord.RichEmbed()
1386 .setColor(locale.info_color)
1387 .setAuthor(`Notes of ${cardUser.username}`, `https://cdn.discordapp.com/avatars/${cardUser.userID}/${cardUser.avatar}.jpg`)
1388 .setDescription(`This user has no Join/Leave history`)
1389 .setTimestamp()
1390 .setFooter(`Gab's Child | Version: ${config.version}`))
1391 }
1392 })
1393 } else if (r.emoji.name == `❌`) {
1394 message.delete();
1395 }
1396 })
1397 });
1398 })
1399 }
1400 } else {
1401 return;
1402 }
1403 }
1404
1405 // Users command
1406 if (command === `users`) {
1407 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1408 if (!args[0]) {
1409 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1410 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1411 } else if (!message.member.roles.some(role => allowedRoles.includes(role.id))) {
1412 return;
1413 }
1414 } else if (args[0] == "count") {
1415 var guild = message.guild.id;
1416 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1417 const usersCountEmbed = new Discord.RichEmbed()
1418 .setColor(locale.info_color)
1419 .setAuthor(locale.bot_name, locale.bot_avatar_link)
1420 .setTitle(`**User count**`)
1421 .addField(`Total user count`, message.guild.memberCount, false)
1422 .setTimestamp()
1423 .setFooter(`Gab's Child | Version: ${config.version}`)
1424 message.channel.send(usersCountEmbed);
1425 }
1426 }
1427 if (args[0] == "update") {
1428 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1429 updateUserTable(`user`, message.channel.id, message.guild.id);
1430 } else {
1431 return;
1432 }
1433 }
1434 }
1435
1436 // Warn command
1437 if (command === `warn`) {
1438 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1439 if (!message.member.roles.some(role => allowedRoles.includes(role.id))) {
1440 return;
1441 } else {
1442 var guild = message.guild;
1443 if (args[0]) {
1444 var user = parseUserTag(args[0]);
1445 } else {
1446 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1447 return;
1448 }
1449 if (user == `err`) {
1450 message.channel.send(`:x: The specified user was not found.`);
1451 } else if (guild.member(user)) {
1452 var tail = args.slice(1);
1453 var content = tail.join(" ").trim();
1454
1455 if (tail.length > 0 && message.member.roles.some(role => allowedRoles.includes(role.id))) {
1456 var identifier = cryptoRandomString({
1457 length: 10
1458 });
1459 var data = [user, message.guild.id, message.author.id, content, identifier, 0, new Date(), user];
1460 connection.query(`INSERT INTO log_warn (userID, guildID, actioner, description, identifier, isDeleted, timestamp) VALUES (?,?,?,?,?,?,?);`, data);
1461
1462 message.channel.send(new Discord.RichEmbed()
1463 .setColor(locale.good_color)
1464 .setAuthor(client.users.get(user).username, client.users.get(user).avatarURL)
1465 .setTitle(`**User warned**`)
1466 .setDescription(`User ${client.users.get(user)} has been successfully warned`)
1467 .addField(`User ID`, `${client.users.get(user).id}`, true)
1468 .addField(`Username`, `${client.users.get(user).username}#${client.users.get(user).discriminator}`, true)
1469 .addField(`Reason`, `${content}`, false)
1470 .addField(`Warned by`, `${message.author}`, false)
1471 .addField(`Identifier`, `${identifier}`, false)
1472 .setTimestamp()
1473 .setFooter(`Gab's Child | Version: ${config.version}`));
1474
1475 client.users.get(user).createDM().then(async chnl => {
1476 await chnl.send(
1477 new Discord.RichEmbed()
1478 .setColor(locale.bad_color)
1479 .setAuthor(locale.bot_name, locale.bot_avatar_link)
1480 .setTitle(`**You have been warned in ${guild.name}**`)
1481 .setDescription(`Details about the warning:`)
1482 .addField(`Warning reason`, `${content}`, false)
1483 .addField(`Identifier`, `${identifier}`, false)
1484 .setTimestamp()
1485 .setFooter(`Gab's Child | Version: ${config.version}`)
1486 ).then(dm => {
1487 var data = [user, message.guild.id, dm.content, 1, 0, identifier, new Date(), new Date()];
1488 connection.query(`INSERT INTO log_outgoingdm(userid, guildID, content, type, isDeleted, identifier, timestamp, updated) VALUES(?,?,?,?,?,?,?,?)`, data);
1489 })
1490 })
1491 } else {
1492 message.channel.send(`:x: Please provide a reason for the warning.`);
1493 }
1494 } else {
1495 message.channel.send(`:x: The specified user was not found.`);
1496 }
1497 }
1498 }
1499
1500 // CWarn command
1501 if (command === `cwarn`) {
1502 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1503 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1504 if (!args[0]) {
1505 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1506 } else if (args[0].length == 10) {
1507 connection.query(`UPDATE log_warn SET isDeleted = 1 WHERE identifier = ? AND guildID = ${message.guild.id}`, args[0].trim(), function (err, results, rows) {
1508 if (err) throw err;
1509 if (results.affectedRows == 0) {
1510 message.channel.send(`:x: Warning could not be found.`);
1511 } else if (results.affectedRows == 1) {
1512 message.channel.send(`:white_check_mark: Warning ID \`${args[0].trim()}\` has been successfully removed.`);
1513 }
1514 });
1515 }
1516 }
1517 }
1518
1519 // Mute command
1520 if (command === `mute`) {
1521 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1522 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1523 if (!args[0] || !args[1]) {
1524 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1525 return;
1526 } else {
1527 var user = parseUserTag(args[0]);
1528 var guild = message.guild;
1529 var guildUser = guild.member(user);
1530
1531 if (user !== `err` && guildUser) {
1532 if (mutedFile.get(user) && mutedFile.get(user).guild == guild.id) {
1533 var existingMute = mutedFile.get(user);
1534 message.channel.send(`:x: User ${client.users.get(user)} is already muted. The mute will end at ${new Date(existingMute.end * 1000)}`);
1535 } else {
1536 var end;
1537 var seconds;
1538 var int = args[1].replace(/[a-zA-Z]$/g, "");
1539
1540 if (parseInt(int)) {
1541 switch ((args[1].toLowerCase().charAt(args[1].length - 1))) {
1542 case "d":
1543 end = ((Math.floor(Date.now() / 1000)) + (int * 24 * 60 * 60));
1544 seconds = (int * 24 * 60 * 60);
1545 break;
1546 case "h":
1547 end = ((Math.floor(Date.now() / 1000)) + (int * 60 * 60));
1548 seconds = (int * 60 * 60);
1549 break;
1550 case "m":
1551 end = ((Math.floor(Date.now() / 1000)) + (int * 60));
1552 seconds = (int * 60);
1553 break;
1554 case "s":
1555 message.channel.send(`:x: The specified mute duration is too short!`);
1556 return;
1557 default:
1558 end = ((Math.floor(Date.now() / 1000)) + (int * 60 * 60));
1559 seconds = (int);
1560 break;
1561 }
1562
1563 var reason = _.rest(args, 2).join(" ");
1564
1565 if (reason.length > 0) {
1566 mutedFile.set(`${user}.end`, end);
1567 mutedFile.set(`${user}.actioner`, message.author.id);
1568 mutedFile.set(`${user}.actionee`, user);
1569 mutedFile.set(`${user}.reason`, reason);
1570 mutedFile.set(`${user}.guild`, guild.id);
1571 mutedFile.save();
1572
1573 var mutedRole = guild.roles.find(val => val.id === config.muted_role);
1574 var identifier = cryptoRandomString({
1575 length: 10
1576 });
1577
1578 guild.member(user).addRole(mutedRole)
1579 .then(member => {
1580 if (member.voiceChannel !== undefined) {
1581 client.channels.get(config.voice_afk).clone(`Disconnecting user...`, false, false, `Disconnecting ${guildUser.user.username}#${guildUser.user.discriminator}`).then(async channel => {
1582 member.setVoiceChannel(channel).then(async () => {
1583 await channel.delete();
1584 })
1585 })
1586 }
1587 message.channel.send(new Discord.RichEmbed()
1588 .setColor(locale.good_color)
1589 .setAuthor(client.users.get(user).username, client.users.get(user).avatarURL)
1590 .setTitle(`**User muted**`)
1591 .setDescription(`User ${client.users.get(user)} has been successfully muted`)
1592 .addField(`User ID`, `${client.users.get(user).id}`, true)
1593 .addField(`Username`, `${client.users.get(user).username}#${client.users.get(user).discriminator}`, true)
1594 .addField(`Reason`, `${reason}`, false)
1595 .addField(`Duration`, `${args[1]}`, false)
1596 .addField(`Muted by`, `${message.author}`, false)
1597 .addField(`Identifier`, `${identifier}`, false)
1598 .setTimestamp()
1599 .setFooter(`Gab's Child | Version: ${config.version}`));
1600 });
1601 var data = [user, guild.id, message.author.id, reason, seconds, identifier, 0, new Date()];
1602 connection.query(`INSERT INTO log_mutes (userID, guildID, actioner, description, length, identifier, isDeleted, timestamp) VALUES (?,?,?,?,?,?,?,?)`, data);
1603
1604 client.users.get(user).createDM().then(async chnl => {
1605 await chnl.send(
1606 new Discord.RichEmbed()
1607 .setColor(locale.bad_color)
1608 .setAuthor(locale.bot_name, locale.bot_avatar_link)
1609 .setTitle(`**You have been muted in ${guild.name}**`)
1610 .setDescription(`Details about the mute:`)
1611 .addField(`Mute reason`, `${reason}`, false)
1612 .addField(`Duration`, `${args[1]}`, false)
1613 .addField(`Identifier`, `${identifier}`, false)
1614 .setTimestamp()
1615 .setFooter(`Gab's Child | Version: ${config.version}`)
1616 ).then(dm => {
1617 if (dm.embeds[0].type === `rich`) {
1618 var data = [user, message.guild.id, dm.embeds[0].title, 3, 0, identifier, new Date(), new Date()];
1619 } else {
1620 var data = [user, message.guild.id, dm.content, 3, 0, identifier, new Date(), new Date()];
1621 }
1622 connection.query(`INSERT INTO log_outgoingdm (userid, guildID, content, type, isDeleted, identifier, timestamp, updated) VALUES (?,?,?,?,?,?,?,?)`, data);
1623 })
1624 })
1625 } else {
1626 message.channel.send(`:x: Please provide a reason for the mute.`);
1627 }
1628 } else {
1629 message.channel.send(`:x: Wrong length syntax.`);
1630 }
1631 }
1632 } else {
1633 message.channel.send(`:x: The specified user was not found.`);
1634 }
1635 }
1636 }
1637 }
1638
1639 // Disconnect command
1640 if (command === `disconnect`) {
1641 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1642 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1643 if (!args[0]) {
1644 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1645 return;
1646 }
1647 var user = parseUserTag(args[0]);
1648 var guild = message.guild;
1649 var guildUser = guild.member(user);
1650
1651 if ((user !== `err` && guildUser) && guildUser.voiceChannel !== undefined) {
1652 client.channels.get(config.voice_afk).clone(`Disconnecting user...`, false, false, `Disconnecting ${guildUser.user.username}#${guildUser.user.discriminator}`).then(async channel => {
1653 guildUser.setVoiceChannel(channel).then(async member => {
1654 await channel.delete();
1655 message.channel.send(`:white_check_mark: User ${member} has been successfully disconnected from their voice channel.`);
1656 })
1657 })
1658 } else {
1659 message.channel.send(`:x: The specified user was not found.`);
1660 }
1661 }
1662 }
1663
1664 // Note command
1665 if (command === `note`) {
1666 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1667 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1668 if (!args[0]) {
1669 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1670 return;
1671 }
1672 if (args[0]) {
1673 var user = parseUserTag(args[0]);
1674 }
1675 if (user == `err`) {
1676 message.channel.send(`:x: The specified user was not found.`);
1677 } else {
1678 var tail = args.slice(1);
1679 var note = tail.join(" ").trim();
1680
1681 if (tail.length > 0) {
1682 var identifier = cryptoRandomString({
1683 length: 10
1684 });
1685 var data = [user, message.guild.id, message.author.id, note, identifier, 0, new Date(), user];
1686 connection.query(`INSERT INTO log_note (userID, guildID, actioner, description, identifier, isDeleted, timestamp) VALUES (?,?,?,?,?,?,?)`, data);
1687
1688 message.channel.send(new Discord.RichEmbed()
1689 .setColor(locale.good_color)
1690 .setAuthor(client.users.get(user).username, client.users.get(user).avatarURL)
1691 .setTitle(`**Note added**`)
1692 .setDescription(`A note was successfully added to ${client.users.get(user)}`)
1693 .addField(`User ID`, `${client.users.get(user).id}`, true)
1694 .addField(`Username`, `${client.users.get(user).username}#${client.users.get(user).discriminator}`, true)
1695 .addField(`Content`, `${note}`, false)
1696 .addField(`Added by`, `${message.author}`, false)
1697 .addField(`Identifier`, `${identifier}`, false)
1698 .setTimestamp()
1699 .setFooter(`Gab's Child | Version: ${config.version}`));
1700 } else {
1701 message.channel.send(`:x: Please provide a reason for the note.`);
1702 }
1703 }
1704 }
1705 }
1706
1707 // CNote command
1708 if (command === `cnote`) {
1709 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1710 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1711 if (!args[0]) {
1712 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1713 return;
1714 }
1715 if (args[0].length == 10) {
1716 connection.query(`UPDATE log_note SET isDeleted = 1 WHERE identifier = ? AND guildID = ${message.guild.id}`, args[0].trim(), function (err, results, rows) {
1717 if (err) throw err;
1718 if (results.affectedRows == 1) {
1719 message.channel.send(`:white_check_mark: Note ID \`${args[0].trim()}\` has been successfully removed.`);
1720 } else {
1721 message.channel.send(`:x: Note could not be found.`);
1722 }
1723 });
1724 }
1725 }
1726 }
1727
1728 // Voicelog command
1729 if (command === `voicelog`) {
1730 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1731 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1732 if (!args[0]) {
1733 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1734 return;
1735 }
1736 if (args[0]) {
1737 var user = parseUserTag(args[0]);
1738 }
1739
1740 if (user == `err`) {
1741 message.channel.send(`:x: The specified user was not found.`);
1742 } else {
1743 connection.query(`SELECT * FROM log_voice WHERE userID = ? AND guildID = ${connection.escape(message.guild.id)} ORDER BY timestamp DESC LIMIT 22`, user, async function (err, rows, results) {
1744 if (err) throw err;
1745
1746 var times = [];
1747 var current = [];
1748 var timestamps = [];
1749 var msg = ["Channel | Timestamp | Duration (H:M:S)",
1750 "------------------------------------------------------------------------------------------------"
1751 ];
1752 for (var i = rows.length - 1; i >= 0; i--) {
1753 var row = rows[i];
1754
1755 if (rows[i - 1]) {
1756 var next = rows[i - 1];
1757
1758 if (row.type !== 3 && ([2, 3].indexOf(next.type) > -1)) {
1759 var time1 = row.timestamp;
1760 var time2 = next.timestamp;
1761
1762 var diff = time2.getTime() - time1.getTime();
1763
1764 var msec = diff;
1765 var hh = Math.floor(msec / 1000 / 60 / 60);
1766 msec -= hh * 1000 * 60 * 60;
1767 var mm = Math.floor(msec / 1000 / 60);
1768 msec -= mm * 1000 * 60;
1769 var ss = Math.floor(msec / 1000);
1770 msec -= ss * 1000;
1771
1772 times.push(`${hh}:${mm}:${ss}`);
1773 current.push(row.newChannel);
1774 timestamps.push(`${row.timestamp.toUTCString()} (${moment(row.timestamp.toUTCString()).fromNow()})`);
1775 }
1776 } else if (!rows[i - 1] && ([1, 2].indexOf(row.type) > -1)) {
1777 current.push(row.newChannel);
1778 times.push(`Active`);
1779 timestamps.push(`${row.timestamp.toUTCString()} (${moment(row.timestamp.toUTCString()).fromNow()})`);
1780 }
1781 }
1782 times.reverse();
1783 current.reverse();
1784 timestamps.reverse();
1785
1786 var longest = 0;
1787 for (var i = 0; i < current.length; i++) {
1788 if (current[i].length > longest) {
1789 longest = current[i].length;
1790 }
1791 }
1792 for (var j = 0; j < current.length; j++) {
1793 var howManyToAdd = longest - current[j].length;
1794 current[j] = current[j].padEnd(current[j].length + howManyToAdd + 1);
1795 }
1796 var longestTime = 0;
1797 for (var i = 0; i < timestamps.length; i++) {
1798 if (current[i].length > longestTime) {
1799 longestTime = timestamps[i].length;
1800 }
1801 }
1802 for (var j = 0; j < timestamps.length; j++) {
1803 var howManyToAdd = longestTime - timestamps[j].length;
1804 timestamps[j] = timestamps[j].padEnd(timestamps[j].length + howManyToAdd + 1);
1805 }
1806 for (var i = 0; i < times.length; i++) {
1807 msg.push(`${current[i]}| ${timestamps[i]}| ${times[i]}`);
1808 }
1809 var joinedMessage = msg.join(`\n`);
1810 message.channel.send(`:microphone2: Viewing voice log of user ${client.users.get(user)} \`\`\`${joinedMessage}\`\`\``);
1811 })
1812 }
1813 }
1814 }
1815
1816 // Badwords command
1817 if (command === `badwords`) {
1818 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1819 if (message.member.roles.some(role => allowedRoles.includes(role.id))) {
1820 if (!args[0]) {
1821 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1822 return;
1823 }
1824 if (args[0] === `add`) {
1825 if (args[1]) {
1826 var checkForDuplicates = args.splice(1);
1827 for (var i = 0; i < checkForDuplicates.length; i++) {
1828 for (var j = 0; j < checkForDuplicates.length; j++) {
1829 if (i != j && checkForDuplicates[i] == checkForDuplicates[j]) {
1830 message.channel.send(`:x: The argument contains duplicates.`);
1831 return;
1832 }
1833 }
1834 }
1835
1836 var bKeys = _.keys(badWordsFile.read());
1837 if (!bKeys || (!bKeys.some(idOfGuild => [message.guild.id].includes(idOfGuild)))) {
1838 badWordsFile.set(`${message.guild.id}.badwords`, checkForDuplicates);
1839 badWordsFile.save();
1840 message.channel.send(`:white_check_mark: Word(s) \`${checkForDuplicates}\`added successfully.`);
1841 return;
1842 }
1843
1844 var currentBadWords = badWordsFile.get(message.guild.id).badwords;
1845 if (currentBadWords.some(word => checkForDuplicates.includes(word))) {
1846 message.channel.send(`:x: One or more words are already on the list.`);
1847 return;
1848 }
1849 currentBadWords = currentBadWords.concat(checkForDuplicates);
1850 badWordsFile.set(`${message.guild.id}.badwords`, currentBadWords);
1851 badWordsFile.save();
1852 message.channel.send(`:white_check_mark: Word(s) \`${checkForDuplicates}\` added successfully.`);
1853 } else message.channel.send(`:x: Please specify a word or words to add.`);
1854 }
1855 if (args[0] === `remove`) {
1856 if (args[1]) {
1857 var checkForDuplicates = args.splice(1);
1858 for (var i = 0; i < checkForDuplicates.length; i++) {
1859 for (var j = 0; j < checkForDuplicates.length; j++) {
1860 if (i != j && checkForDuplicates[i] == checkForDuplicates[j]) {
1861 message.channel.send(`:x: The argument contains duplicates.`);
1862 return;
1863 }
1864 }
1865 }
1866 var removed = 0;
1867 var currentBadWords = badWordsFile.get(message.guild.id).badwords;
1868 var numberOfElements = 0;
1869 for (var i = 0; i < checkForDuplicates.length; i++) {
1870 for (var j = 0; j < currentBadWords.length; j++) {
1871 if (checkForDuplicates[i] === currentBadWords[j]) numberOfElements++;
1872 }
1873 }
1874 if (numberOfElements < checkForDuplicates.length) {
1875 message.channel.send(`:x: One or more words are not on the list.`)
1876 return;
1877 }
1878 for (var i = 0; i < currentBadWords.length; i++) {
1879 for (var j = 0; j < checkForDuplicates.length; j++) {
1880 if (currentBadWords[i] === checkForDuplicates[j]) {
1881 currentBadWords.splice(i, 1);
1882 badWordsFile.set(`${message.guild.id}.badwords`, currentBadWords);
1883 removed = 1;
1884 }
1885 }
1886 }
1887 badWordsFile.save();
1888 if (removed == 1) {
1889 message.channel.send(`:white_check_mark: All words \`${checkForDuplicates}\` removed successfully.`);
1890 }
1891 } else message.channel.send(`:x: Please specify a word to remove.`);
1892 }
1893 if (args[0] === "clear") {
1894 if(badWordsFile.get(message.guild.id)) {
1895 badWordsFile.unset(message.guild.id);
1896 badWordsFile.save();
1897 message.channel.send(`:white_check_mark: All bad words removed successfully.`);
1898 return;
1899 }
1900 message.channel.send(`There are no bad words.`)
1901 }
1902 if (args[0] === "list") {
1903 if(!_.keys(badWordsFile.read()).some(guildId => [message.guild.id].includes(guildId))) {
1904 const badWordsListEmbed = new Discord.RichEmbed()
1905 .setColor(locale.info_color)
1906 .setAuthor(locale.bot_name, locale.bot_avatar_link)
1907 .setTitle(`**Bad words**`)
1908 .setDescription(`There are no bad words`)
1909 .setTimestamp()
1910 .setFooter(`Gab's Child | Version: ${config.version}`);
1911
1912 message.channel.send(badWordsListEmbed);
1913 return;
1914 }
1915 badWords = badWordsFile.get(message.guild.id).badwords;
1916 if (badWords.length > 0) {
1917 const badWordsListEmbed = new Discord.RichEmbed()
1918 .setColor(locale.info_color)
1919 .setAuthor(locale.bot_name, locale.bot_avatar_link)
1920 .setTitle(`**Bad words:**`)
1921 .setDescription(badWords)
1922 .setTimestamp()
1923 .setFooter(`Gab's Child | Version: ${config.version}`);
1924
1925 message.channel.send(badWordsListEmbed);
1926 } else {
1927 const badWordsListEmbed = new Discord.RichEmbed()
1928 .setColor(locale.info_color)
1929 .setAuthor(locale.bot_name, locale.bot_avatar_link)
1930 .setTitle(`**Bad words**`)
1931 .setDescription(`There are no bad words`)
1932 .setTimestamp()
1933 .setFooter(`Gab's Child | Version: ${config.version}`);
1934
1935 message.channel.send(badWordsListEmbed);
1936 }
1937 }
1938 }
1939 }
1940
1941 // Channels command
1942 if (command === `bot`) {
1943 var guild = message.guild;
1944 if(_.keys(allowedRolesFile.read()).some(guildId => [message.guild.id].includes(guildId))) {
1945 var allowedRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
1946 if((allowedRoles.length > 0)) {
1947 if (!message.member.roles.some(role => allowedRoles.includes(role.id))) return;
1948 } else if (guild.ownerID != message.author.id) return;
1949 } else if (guild.ownerID != message.author.id) return;
1950 if (!args[0]) {
1951 message.channel.send(`:x: Wrong command syntax. Please use \`${config.prefix}help\` to view all commands.`);
1952 }
1953 if(args[0] === `channel`) {
1954 if (args[1] === `set`) {
1955 if (args[2] === `server_log`) {
1956 channelsFile.set(guild.id, {
1957 server_log: message.channel.id
1958 });
1959 channelsFile.save();
1960 message.channel.send(`:white_check_mark: Server Log channel has been successfully set.`);
1961 } else if (args[2] === `bot_log`) {
1962 channelsFile.set(guild.id, {
1963 bot_log: message.channel.id
1964 });
1965 channelsFile.save();
1966 message.channel.send(`:white_check_mark: Bot Log channel has been successfully set.`);
1967 } else {
1968 message.channel.send(`:x: Please specify what to set.`);
1969 }
1970 }
1971 } else if (args[0] === `role`) {
1972 if (args[1] === `add`) {
1973 if ((args[2])) {
1974 var checkForDuplicates = args.splice(2);
1975 for (var i = 0; i < checkForDuplicates.length; i++) {
1976 for (var j = 0; j < checkForDuplicates.length; j++) {
1977 if (i != j && checkForDuplicates[i] == checkForDuplicates[j]) {
1978 message.channel.send(`:x: The argument contains duplicates.`);
1979 return;
1980 }
1981 }
1982 }
1983 }
1984 var rKeys = _.keys(allowedRolesFile.read());
1985 if (!rKeys || (!rKeys.some(idOfGuild => [message.guild.id].includes(idOfGuild)))) {
1986 allowedRolesFile.set(guild.id, {
1987 allowedRoles: checkForDuplicates
1988 });
1989 allowedRolesFile.save();
1990 message.channel.send(`:white_check_mark: Administrator role has been successfully added.`);
1991 } else {
1992 var array = allowedRolesFile.get(message.guild.id).allowedRoles;
1993 if (checkForDuplicates.some(value => array.includes(value))) {
1994 message.channel.send(`:x: One of the roles is already set.`);
1995 return;
1996 }
1997 array = array.concat(checkForDuplicates);
1998 allowedRolesFile.set(guild.id, {
1999 allowedRoles: array
2000 });
2001 allowedRolesFile.save();
2002 message.channel.send(`:white_check_mark: Administrator role has been successfully added.`);
2003 }
2004 } else if (args[1] === `remove`) {
2005 if (args[2]) {
2006 var checkForDuplicates = args.splice(2);
2007 for (var i = 0; i < checkForDuplicates.length; i++) {
2008 for (var j = 0; j < checkForDuplicates.length; j++) {
2009 if (i != j && checkForDuplicates[i] == checkForDuplicates[j]) {
2010 message.channel.send(`:x: The argument contains duplicates.`);
2011 return;
2012 }
2013 }
2014 }
2015 var removed = 0;
2016 var rKeys = _.keys(allowedRolesFile.read());
2017 if (rKeys.some(idOfGuild => [message.guild.id].includes(idOfGuild))) {
2018 var currentRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
2019 var numberOfElements = 0;
2020 for (var i = 0; i < checkForDuplicates.length; i++) {
2021 for (var j = 0; j < currentRoles.length; j++) {
2022 if (checkForDuplicates[i] == currentRoles[j]) numberOfElements++;
2023 }
2024 }
2025 if (numberOfElements < checkForDuplicates.length) {
2026 message.channel.send(`:x: One or more roles are not set.`)
2027 return;
2028 }
2029 for (var i = 0; i < currentRoles.length; i++) {
2030 for (var j = 0; j < checkForDuplicates.length; j++) {
2031 if (currentRoles[i] === checkForDuplicates[j]) {
2032 currentRoles.splice(i, 1);
2033 allowedRolesFile.set(`${message.guild.id}.allowedRoles`, currentRoles);
2034 removed = 1;
2035 }
2036 }
2037 }
2038 allowedRolesFile.save();
2039 if (removed == 1) {
2040 message.channel.send(`:white_check_mark: All specified roles removed successfully.`);
2041 }
2042 }
2043 }
2044 } else if (args[1] === `list`) {
2045 var currentRoles = allowedRolesFile.get(message.guild.id).allowedRoles;
2046 var listOfRoles = ``;
2047 var idOfRoles = ``;
2048 for (var i = 0; i < currentRoles.length; i++) {
2049 if (i == 0) {
2050 listOfRoles += `${message.guild.roles.get(currentRoles[i])}`;
2051 idOfRoles += `${currentRoles[i]}`;
2052 } else {
2053 listOfRoles += `, ${message.guild.roles.get(currentRoles[i])}`;
2054 idOfRoles += `, ${currentRoles[i]}`;
2055 }
2056 }
2057 if (listOfRoles === ``) {
2058 listOfRoles = `List of Roles is empty.`
2059 idOfRoles = `List of IDs is empty.`
2060 }
2061 const rolesListEmbed = new Discord.RichEmbed()
2062 .setColor(locale.info_color)
2063 .setAuthor(client.user.username, client.user.displayAvatarURL)
2064 .setTitle(`**Current roles with access to administrator commands:**`)
2065 .addField(`Role names: `, listOfRoles)
2066 .addField(`Role IDs: `, idOfRoles)
2067 .setTimestamp()
2068 .setFooter(`Gab's Child | Version: ${config.version}`)
2069 message.channel.send(rolesListEmbed);
2070 return;
2071 } else {
2072 message.channel.send(`:x: Please specify what to set.`);
2073 }
2074 }
2075 }
2076});
2077
2078// User Join Listener Event
2079client.on(`guildMemberAdd`, member => {
2080 var gKeys = _.keys(channelsFile.read());
2081 for (var i = 0; i < gKeys.length; i++) {
2082 var guild = gKeys[i];
2083
2084 if (member.guild.id == guild) {
2085 var params = [member.user.id, guild, member.user.username, member.user.avatar, 1, new Date(), member.user.id, member.user.id, guild, new Date()];
2086 connection.query(
2087 `
2088 INSERT IGNORE INTO users (userID, guildID, username, avatar, exist, timestamp) VALUES (?,?,?,?,?,?);
2089 UPDATE users SET exist = 1 WHERE userID = ?;
2090 INSERT INTO log_guildjoin (userID, guildID, timestamp) VALUES (?,?,?);
2091 `, params
2092 );
2093
2094 const userJoinEmbed = new Discord.RichEmbed()
2095 .setColor(locale.good_color)
2096 .setAuthor(member.user.username, member.user.avatarURL)
2097 .setTitle(`**User has joined**`)
2098 .setDescription(`${member} has joined ${member.guild.name}`)
2099 .setTimestamp()
2100 .setFooter(`Gab's Child | Version: ${config.version}`);
2101
2102 client.channels.get(channelsFile.get(guild).server_log).send(userJoinEmbed);
2103 } else {
2104 return;
2105 }
2106 }
2107});
2108
2109// User Left Listener Event
2110client.on(`guildMemberRemove`, member => {
2111 var data = [member.user.id, member.guild.id, new Date()];
2112 var userLeave = [0, member.user.id, member.guild.id];
2113
2114 connection.query(
2115 `INSERT INTO log_guildleave (userID, guildID, timestamp) VALUES (?,?,?)`, data
2116 );
2117 connection.query(
2118 `UPDATE users SET exist = ? WHERE userID = ? AND guildID = ?`, userLeave
2119 );
2120
2121 const userLeaveEmbed = new Discord.RichEmbed()
2122 .setColor(locale.bad_color)
2123 .setAuthor(member.user.username, member.user.avatarURL)
2124 .setTitle(`**User has left**`)
2125 .setDescription(`${member} has left ${member.guild.name}`)
2126 .setTimestamp()
2127 .setFooter(`Gab's Child | Version: ${config.version}`);
2128
2129 var guild = member.guild.id;
2130 client.channels.get(channelsFile.get(guild).server_log).send(userLeaveEmbed);
2131});
2132
2133client.on(`voiceStateUpdate`, function (oldMember, newMember) {
2134 var data = [];
2135 if (oldMember.voiceChannel) {
2136 if (newMember.voiceChannel) {
2137 if (oldMember.voiceChannel.id !== newMember.voiceChannel.id) {
2138 data = [newMember.id, newMember.guild.id, newMember.voiceChannel.id, newMember.voiceChannel.name, oldMember.voiceChannel.id, oldMember.voiceChannel.name, 2, new Date()];
2139 } else {
2140 return;
2141 }
2142 } else {
2143 data = [newMember.id, newMember.guild.id, ``, ``, oldMember.voiceChannel.id, oldMember.voiceChannel.name, 3, new Date()];
2144 }
2145 } else if (newMember.voiceChannel) {
2146 data = [newMember.id, newMember.guild.id, newMember.voiceChannel.id, newMember.voiceChannel.name, ``, ``, 1, new Date()];
2147 } else {
2148 data = [newMember.id, newMember.guild.id, `Unknown`, `Unknown`, ``, ``, 1, new Date()];
2149 }
2150 if (data.length > 0) {
2151 connection.query(
2152 `INSERT INTO log_voice (userID, guildID, newChannelID, newChannel, oldChannelID, oldChannel, type, timestamp ) VALUES (?,?,?,?,?,?,?,?)`, data
2153 );
2154 }
2155});
2156
2157// Message Deletion Listener Event
2158client.on(`messageDelete`, async message => {
2159 const entry = await message.guild.fetchAuditLogs({
2160 type: 'MESSAGE_DELETE'
2161 }).then(audit => audit.entries.first())
2162 let user = ""
2163 if (deletedByBot == 1) {
2164 user = client.user;
2165 deletedByBot = 0;
2166 } else if (entry.extra.channel.id === message.channel.id &&
2167 (entry.target.id === message.author.id) &&
2168 (entry.createdTimestamp > (Date.now() - 5000)) &&
2169 (entry.extra.count >= 1)) {
2170 user = entry.executor
2171 } else {
2172 user = message.author
2173 }
2174
2175 if (message.author.bot) {
2176 return;
2177 }
2178
2179 const messageDeleteEmbed = new Discord.RichEmbed()
2180 .setColor(locale.info_color)
2181 .setAuthor(message.author.username, message.author.avatarURL)
2182 .setTitle(`**Message deleted in #${message.channel.name}**`)
2183 .setDescription(`Message sent by ${message.member} deleted in ${message.channel}
2184 **Deleted by:** ${user}
2185 **Deleted message:** ${message}`)
2186 .setTimestamp()
2187 .setFooter(`Gab's Child | Version: ${config.version}`);
2188
2189 var guild = message.guild.id;
2190 client.channels.get(channelsFile.get(guild).server_log).send(messageDeleteEmbed);
2191});
2192
2193// Message Edit Listener Event
2194client.on(`messageUpdate`, function (oldMessage, newMessage) {
2195 if (oldMessage.content === newMessage.content) return;
2196 const messageEditEmbed = new Discord.RichEmbed()
2197 .setColor(locale.info_color)
2198 .setAuthor(oldMessage.author.username, oldMessage.author.avatarURL)
2199 .setTitle(`**Message edited in #${oldMessage.channel.name}**`)
2200 .setDescription(`Message sent by ${oldMessage.member} edited in ${oldMessage.channel}
2201 **Old message:** ${oldMessage}
2202 **New message:** ${newMessage}\n
2203 [Jump to Message](https://discordapp.com/channels/${config.guild}/${newMessage.channel.id}/${newMessage.id})`)
2204 .setTimestamp()
2205 .setFooter(`Gab's Child | Version: ${config.version}`);
2206
2207 var guild = oldMessage.guild.id;
2208 client.channels.get(channelsFile.get(guild).server_log).send(messageEditEmbed);
2209});
2210
2211client.on(`userUpdate`, function (oldUser, newUser) {
2212 if (oldUser.username !== newUser.username) {
2213 var data = [newUser.id, newUser.guild.id, newUser.username, oldUser.username, new Date()];
2214 connection.query(
2215 `INSERT INTO log_username (userID, guildID, new, old, timestamp) VALUES (?,?,?,?,?)`, data
2216 )
2217 }
2218 if (oldUser.avatar !== newUser.avatar) {
2219 var data = [newUser.avatar, new Date(), newUser.id];
2220 connection.query(
2221 `UPDATE users SET avatar = ?, updated = ? WHERE userID = ?`, data
2222 )
2223 }
2224});
2225
2226client.on(`guildMemberUpdate`, function (oldMember, newMember) {
2227 if (oldMember.displayName !== newMember.displayName) {
2228 var data = [newMember.user.id, newMember.guild.id, newMember.displayName, oldMember.displayName, new Date()];
2229 connection.query(
2230 `INSERT INTO log_nickname (userID, guildID, new, old, timestamp) VALUES (?,?,?,?,?)`, data
2231 )
2232 const messageEditEmbed = new Discord.RichEmbed()
2233 .setColor(locale.info_color)
2234 .setAuthor(newMember.user.username, newMember.user.avatarURL)
2235 .setTitle(`**Nickname change**`)
2236 .setDescription(`User ${newMember.user} has changed their nickname
2237 **Old nickname:** ${oldMember.displayName}
2238 **New nickname:** ${newMember.displayName}`)
2239 .setTimestamp()
2240 .setFooter(`Gab's Child | Version: ${config.version}`);
2241
2242 var guild = oldMember.guild.id;
2243 client.channels.get(channelsFile.get(guild).server_log).send(messageEditEmbed);
2244 }
2245});
2246
2247client.on(`error`, console.error);
2248client.on(`warn`, warn => {
2249 console.log(warn);
2250});
2251
2252// Login
2253client.login(config.token);