· 5 years ago · Sep 14, 2020, 03:48 PM
1const Discord = require('discord.js')
2const FS = require('fs')
3const rp = require('request-promise')
4const $ = require('cheerio')
5const mysql = require('mysql')
6require('events').EventEmitter.prototype._maxListeners = 0
7
8// MySQL Connection Settings
9var pool = mysql.createPool({
10 connectionLimit: 500,
11 host: '',
12 user: '',
13 password: '',
14 database: '',
15})
16
17// Boolean variables used for state checking
18var emptyQueue = true
19var handlingQueue = false
20var updatingRanks = false
21var checkingHighest = false
22var checkingRoles = false
23var enabled = true
24
25const platforms = ['steam', 'ps', 'xbox']
26
27const modes = ['Standard', 'Doubles', 'Solo Duel']
28
29const ranks = ['Bronze', 'Silver', 'Gold', 'Platinum', 'Diamond', 'Champion']
30const rankColors = ['#d6680e', '#9aaab4', '#eec42c', '#00d5eb', '#4198d9', '#9a58b4']
31
32const ranks2 = ['Unranked', 'Bronze', 'Silver', 'Gold', 'Platinum', 'Diamond', 'Champion', 'Grand Champion']
33const rankColors2 = ['#627d8a', '#d6680e', '#9aaab4', '#eec42c', '#00d5eb', '#4198d9', '#9a58b4', '#703589']
34
35var rankValues = [] // is filled in by SetRankValues()
36
37const tiers = ['I', 'II', 'III']
38
39const URL = 'https://rocketleague.tracker.network/rocket-league/profile/'
40const currentSeason = '14' // Update to current season when it changes
41
42const TOKEN = '' // Fill with your discord app Token
43const ServerID = '' // ID of the server you want to use the bot in
44var bot = new Discord.Client()
45bot.login(TOKEN)
46
47var z = 0
48
49bot.on('ready', function () {
50 console.log('RL Stats Activated.')
51
52 // Verify log.txt exists or create it
53 VerifyLogFile()
54 UpdateLogFile('RL Stats Activated.')
55
56 SetRankValues()
57
58
59 // Production Intervals
60 /*setInterval(async function(){ emptyQueue = await CheckQueue() }, 60*1000)
61 setInterval(async function(){ if (!handlingQueue) { HandleQueue() } }, 2*60*1000)
62 setInterval(async function(){ if (!updatingRanks) { UpdateUsers() } }, 15*60*1000)
63 setInterval(async function(){ if (!checkingHighest) { CheckHighest() } }, 5*60*1000)
64 setInterval(async function(){ if (!checkingRoles) { CheckRoles() } }, 10*60*1000)
65
66 //Testing with shorter times
67 setInterval(async function () { emptyQueue = await CheckQueue() }, 20 * 1000)
68 setInterval(async function () { if (!handlingQueue) { HandleQueue() } }, 60 * 1000)
69 setInterval(async function () { if (!updatingRanks) { UpdateUsers() } }, 2*60 * 1000)
70 setInterval(async function () { if (!checkingHighest) { CheckHighest() } }, 3*60 * 1000)
71 setInterval(async function () { if (!checkingRoles) { CheckRoles() } }, 90 * 1000)*/
72
73 setInterval(async function () { emptyQueue = await CheckQueue() }, 15 * 1000)
74 setInterval(async function () { if (!handlingQueue) { HandleQueue() } }, 40 * 1000)
75 setInterval(async function () { if (!updatingRanks) { UpdateUsers() } }, 90 * 1000)
76 setInterval(async function () { if (!checkingHighest) { CheckHighest() } }, 1*60 * 1000)
77 setInterval(async function () { if (!checkingRoles) { CheckRoles() } }, 60 * 1000)
78})
79
80bot.on('disconnect', function () {
81 UpdateLogFile('RL Stats Deactivated.')
82 enabled = false
83})
84
85bot.on('reconnecting', function () {
86 UpdateLogFile('RL Stats Reconnecting.')
87 enable = false
88})
89
90bot.on('resume', function () {
91 UpdateLogFile('RL Stats Resumed.')
92 enabled = false
93})
94
95bot.on('error', function (error) {
96 console.log(error.message)
97 UpdateLogFile(error.message)
98 enabled = false
99})
100
101bot.on('message', function (message) {
102
103 // Do nothing if the message is from the bot
104 if (message.author.equals(bot.user)) {
105 return
106 }
107
108 // Ignore all messages unless they start with '!rl'
109 if (message.content.toLowerCase().startsWith('!rl')) {
110
111 // Help command
112 if (message.content.toLowerCase() === '!rlhelp') {
113 var embed = new Discord.RichEmbed()
114 .setColor('#0291ED')
115 .addField('This is RL Stats!', "I will keep your Rocket League competitive ranks updated for you in this Discord server!")
116 .addField('Commands',
117 '!rlregister <Platform> <Account Name>')
118 .addField('Note',
119 '**Available Platforms**: `steam`, `ps`, `xbox`\n' +
120 'If you are on steam: Make sure to give your __Account Name__ and not your profile name.\n' +
121 'For a complete guide to setting up your Steam Account (if applicable) and Rocket League Tracker Network account to work with RL Stats, click the link below.\n' +
122 'https://docs.google.com/document/d/1wvKjSyu7Iig0qY9T4bFf7Z-EwM1KRrvZqbcbfqK7ssY/edit?usp=sharing')
123 message.channel.send(embed)
124 }
125
126 // Command for building all necessary roles
127 // Must have a role called 'Admin' to be able to use it
128 if (message.content.toLowerCase() == '!rlsetuproles') {
129 if (UserIsAdmin(message)) {
130 BuildRoleNames(message)
131 message.channel.send('All rank roles have been created.')
132 } else {
133 message.channel.send(message.member.toString() + ' You are not an admin user!')
134 }
135 }
136
137 // Command for deleting all roles created by the bot
138 // Must have a role called 'Admin' to be able to use it
139 if (message.content.toLowerCase() == '!rlcleanroles') {
140 if (UserIsAdmin(message)) {
141 DeleteRoles(message)
142 message.channel.send('All rank roles have been deleted.')
143 } else {
144 message.channel.send(message.member.toString() + ' You are not an admin user!')
145 }
146 }
147 if (message.content.toLowerCase() == '!rlenable') {
148 if (UserIsAdmin(message)) {
149 enabled = true;
150 message.channel.send('Der Bot wurde wieder Aktiviert.')
151 } else {
152 message.channel.send(message.member.toString() + ' You are not an admin user!')
153 }
154 }
155
156 // Command for registering users with the bot
157 if (message.content.toLowerCase().startsWith('!rlregister')) {
158 // Verify no users are mentioned in the message
159 if (UserMentioned(message)) {
160 message.channel.send('User mentions are not supported!')
161 } else {
162 var fullCommand = message.content.split(' ')
163 // Verify the correct amount of arguments were given
164 if (fullCommand.length != 3) {
165 message.channel.send('Incorrect amount of arguments!\nExpected: `2`\nGiven: `' + (fullCommand.length - 1) + '`')
166 } else {
167 // Command should look like "!rlregister steam jeremyd4500"
168 var Platform = fullCommand[1].toLowerCase() // steam
169 var AccountID = fullCommand[2].toLowerCase() // jeremyd4500
170 // Verify the platform is one of the available options
171 if (platforms.includes(Platform)) {
172 // Attempt to access a URL similar to 'https://rocketleague.tracker.network/profile/steam/jeremyd4500'
173 rp(URL + '/' + Platform + '/' + AccountID + '/overview')
174 .then(function (html) {
175 if (html.includes('We could not find your stats')) { // This page is shown with an invalid URL
176 message.channel.send("I'm sorry. I could not find **" + AccountID + "** in the tracker network.")
177 } else {
178 // Add new user to the queue table
179 AddUserToQueue(message.member.id, Platform, AccountID)
180 message.channel.send("Added stat request for **" + AccountID + "** under " + message.member.toString() + ' to the queue!')
181 }
182 })
183 .catch(function (error) {
184 UpdateLogFile(error)
185 })
186 } else {
187 message.channel.send('That is not a correct platform!\nPlatform Options: `steam`,`ps`,`xbox`')
188 }
189 }
190 }
191 }
192 }
193})
194
195// SQL Query
196// Updates the "Highest" column for the appropriate user
197function AddHighest(DiscordID, rank) {
198 UpdateLogFile('Function Call: AddHighest()')
199 return new Promise(resolve => {
200 pool.getConnection(async function (error, connection) {
201 if (error) { UpdateLogFile(error) } else {
202 var ID = await GetUserID(DiscordID)
203 connection.query("update ranks set Highest = '" + rank + "' where UserID = " + ID, function (error, results, fields) {
204 connection.release()
205 if (error) { UpdateLogFile(error) }
206 })
207 }
208 })
209 setTimeout(() => {
210 resolve(UpdateLogFile('SQL Query: Successfully updated Highest to value ' + rank + ' for user ' + DiscordID))
211 }, 5000)
212 })
213}
214
215// SQL Query
216// Inserts "Unranked" into all rank columns for a new user
217function AddRanksToUser(DiscordID) {
218 UpdateLogFile('Function Call: AddRanksToUser()')
219 return new Promise(resolve => {
220 pool.getConnection(async function (error, connection) {
221 if (error) { UpdateLogFile(error) } else {
222 var ID = await GetUserID(DiscordID)
223 connection.query("insert into ranks (UserID,Highest,Standard,Doubles,SoloDuel,SoloStandard,Rumble,Dropshot,Hoops,SnowDay) values ('" + ID + "','Unranked','Unranked','Unranked','Unranked','Unranked','Unranked','Unranked','Unranked','Unranked')", function (error, results, fields) {
224 connection.release()
225 if (error) { UpdateLogFile(error) }
226 })
227 }
228 })
229 setTimeout(() => {
230 resolve(UpdateLogFile('SQL Query: Successfully added blank ranks for user ' + DiscordID))
231 }, 5000)
232 })
233}
234
235// Discord Process
236// Adds a new role to the server if it doesn't already exist
237function AddRole(message, RoleName, color) {
238 var role = message.guild.roles.find(role => role.name === RoleName)
239 if (role) {
240 UpdateLogFile("Role '" + RoleName + "' already exists!")
241 } else {
242 message.guild.createRole({
243 name: RoleName,
244 color: color
245 })
246 UpdateLogFile("Role '" + RoleName + "' has been created!")
247 }
248}
249
250// Discord Process
251// Adds a role to a user if it exists
252function AddRoleToUser(DiscordID, RoleName) {
253 UpdateLogFile('Function Call: AddRoleToUser()')
254 return new Promise(resolve => {
255 var success = false
256 let newRole = bot.guilds.get(ServerID).roles.find(role => role.name === RoleName).id
257 if (newRole) {
258 bot.guilds.get(ServerID).members.get(DiscordID).addRole(newRole)
259 success = true
260 } else {
261 UpdateLogFile('Role ' + RoleName + ' does not exist')
262 success = false
263 }
264 setTimeout(() => {
265 if (success) {
266 resolve(UpdateLogFile('Discord Process: Successfully added role ' + RoleName + ' to user ' + DiscordID))
267 } else {
268 resolve(UpdateLogFile('Discord Process: Failed to add role ' + RoleName + ' to user ' + DiscordID))
269 }
270 }, 2000)
271 })
272}
273
274// SQL Query
275// Adds a user from the queue table to the users table and then inserts blank ranks for them
276function AddUser(DiscordID, Platform, AccountID) {
277 UpdateLogFile('Function Call: AddUser()')
278 return new Promise(resolve => {
279 pool.getConnection(function (error, connection) {
280 if (error) { UpdateLogFile(error) } else {
281 connection.query("insert into users (DiscordID,Platform,AccountID) values ('" + DiscordID + "','" + Platform + "','" + AccountID + "')", async function (error, results, fields) {
282 connection.release()
283 if (error) { UpdateLogFile(error) } else {
284 await AddRanksToUser(DiscordID)
285 }
286 })
287 }
288 })
289 setTimeout(() => {
290 resolve(UpdateLogFile('SQL Query: Successfully added user ' + DiscordID + ' to the database'))
291 }, 5000)
292 })
293}
294
295// SQL Query
296// Updates any column for a user in the users table
297function AddUserDetail(ID, column, value) {
298 UpdateLogFile('Function Call: AddUserDetail()')
299 return new Promise(resolve => {
300 pool.getConnection(async function (error, connection) {
301 if (error) { UpdateLogFile(error) } else {
302 connection.query("update users set " + column + " = '" + value + "' where ID = " + ID, function (error, results, fields) {
303 connection.release()
304 if (error) { UpdateLogFile(error) }
305 })
306 }
307 })
308 setTimeout(() => {
309 resolve(UpdateLogFile('SQL Query: Successfully updated detail ' + column + ' with value ' + value + ' for user ' + ID))
310 }, 5000)
311 })
312}
313
314// SQL Query
315// Updates any column for a user in the ranks table
316function AddUserStat(UserID, column, value, rating) {
317 UpdateLogFile('Function Call: AddUserStat()')
318 return new Promise(resolve => {
319 pool.getConnection(async function (error, connection) {
320 if (error) { UpdateLogFile(error) } else {
321 connection.query("update ranks set " + column + " = '" + value + "' where UserID = " + UserID, function (error, results, fields) {
322 connection.release()
323 if (error) { UpdateLogFile(error) }
324 })
325 }
326 })
327 setTimeout(() => {
328 resolve(UpdateLogFile('SQL Query: Successfully updated stat ' + column + ' with value ' + value + ' for user ' + UserID))
329 }, 5000)
330 })
331}
332
333// SQL Query
334// Adds a new user to the queue table
335function AddUserToQueue(DiscordID, Platform, AccountID) {
336 UpdateLogFile('Function Call: AddUserToQueue()')
337 return new Promise(resolve => {
338 pool.getConnection(async function (error, connection) {
339 if (error) { UpdateLogFile(error) } else {
340 connection.query("insert into queue (DiscordID,Platform,AccountID) values ('" + DiscordID + "','" + Platform + "','" + AccountID + "')", function (error, results, fields) {
341 connection.release()
342 if (error) { UpdateLogFile(error) }
343 })
344 }
345 })
346 setTimeout(() => {
347 resolve(UpdateLogFile('SQL Query: Successfully added queue entry for user ' + DiscordID))
348 }, 5000)
349 })
350}
351
352// Javascript
353// Creates all roles needed by the bot and calls AddRole() for each
354function BuildRoleNames(message) {
355 UpdateLogFile('Function Call: BuildRoleNames()')
356 // First add the "Highest" roles
357 for (let i = ranks2.length - 1; i >= 0; i--) {
358 AddRole(message, ranks2[i], rankColors2[i])
359 }
360 // Then add all the rank roles
361 for (let i = 0; i < modes.length; i++) {
362 var currentRole = modes[i] + ' Unranked'
363 AddRole(message, currentRole, '#627d8a')
364 for (let j = 0; j < ranks.length; j++) {
365 for (let k = 0; k < tiers.length; k++) {
366 currentRole = modes[i] + ' ' + ranks[j] + ' ' + tiers[k]
367 AddRole(message, currentRole, rankColors[j])
368 }
369 }
370 currentRole = modes[i] + ' Grand Champion'
371 AddRole(message, currentRole, '#703589')
372 }
373}
374
375// Javascript
376// Gets an array of Discord ID's from the users table and calls UpdateHighest() for each
377async function CheckHighest() {
378 checkingHighest = true
379 var users = await GetUsers()
380 for (let i = 0; i < users.length; i++) {
381 await UpdateHighest(users[i])
382 }
383 checkingHighest = false
384}
385
386// SQL Query
387// Checks if the queue table is empty
388function CheckQueue() {
389 UpdateLogFile('Function Call: CheckQueue()')
390 return new Promise(resolve => {
391 var isEmpty = true
392 pool.getConnection(function (error, connection) {
393 if (error) { UpdateLogFile(error) } else {
394 connection.query('select * from queue', function (error, results, fields) {
395 connection.release()
396 if (error) { UpdateLogFile(error) } else {
397 if (results.length > 0) {
398 isEmpty = false
399 }
400 UpdateLogFile('SQL Query: Successfully retrieved the queue')
401 }
402 })
403 }
404 })
405 setTimeout(() => {
406 resolve(isEmpty)
407 }, 5000)
408 })
409}
410
411// Javascript
412// Gets an array of Discord ID's from the users table and calls UpdateRankRoles() for each
413async function CheckRoles() {
414 z = z + 1
415 var CurrentTime = new Date()
416 var today = CurrentTime.getDate().toString() + '/' + (CurrentTime.getMonth() + 1).toString() + '/' + CurrentTime.getFullYear().toString()
417 var ClockTime = CurrentTime.getHours().toString() + ':' + CurrentTime.getMinutes().toString() + ':' + CurrentTime.getSeconds().toString()
418 var FullTime = today + ' ' + ClockTime + ' >>> '
419 console.log("Roles werden gecheckt (" + FullTime + z + ")")
420 checkingRoles = true
421 var users = await GetUsers()
422 for (let i = 0; i < users.length; i++) {
423 await UpdateRankRoles(users[i])
424 }
425 checkingRoles = false
426}
427
428// Discord Process
429// Deletes a role created by the bot if it exists
430function DeleteRole(message, roleName) {
431 var role = message.guild.roles.find(role => role.name === roleName)
432 if (role) {
433 role.delete()
434 UpdateLogFile("Role '" + roleName + "' has been deleted!")
435 } else {
436 UpdateLogFile("Role '" + roleName + "' does not exist!")
437 }
438}
439
440// Javascript
441// Creates the name of each role created by the bot and calls DeleteRole() for each
442function DeleteRoles(message) {
443 // First delete the "Highest" roles
444 for (let i = ranks2.length - 1; i >= 0; i--) {
445 DeleteRole(message, ranks2[i])
446 }
447 // Then delete the rank roles
448 for (let i = 0; i < modes.length; i++) {
449 var currentRole = modes[i] + ' Unranked'
450 DeleteRole(message, currentRole)
451 for (let j = 0; j < ranks.length; j++) {
452 for (let k = 0; k < tiers.length; k++) {
453 currentRole = modes[i] + ' ' + ranks[j] + ' ' + tiers[k]
454 DeleteRole(message, currentRole)
455 }
456 }
457 currentRole = modes[i] + ' Grand Champion'
458 DeleteRole(message, currentRole)
459 }
460}
461
462// Javascript
463// Updates the Platform and AccoundID for a user
464// Calls AddUserStat() to inserts "Unranked" for all ranks for a user
465async function EditUser(DiscordID, Platform, AccountID) {
466 UpdateLogFile('Function Call: EditUser()')
467 var ID = await GetUserID(DiscordID)
468 await AddUserDetail(ID, 'Platform', Platform)
469 await AddUserDetail(ID, 'AccountID', AccountID)
470 var SQLRanks = []
471 modes.forEach(function (item) {
472 SQLRanks.push(item)
473 })
474 SQLRanks.push('Highest')
475 SQLRanks.forEach(async function (item) {
476 item = item.replace(' ', '')
477 await AddUserStat(ID, item, 'Unranked', 0)
478 })
479}
480
481// SQL Query
482// Retrieves the value in the "Highest" column for a user in the ranks table
483function GetHighest(DiscordID) {
484 UpdateLogFile('Function Call: GetHighest()')
485 return new Promise(resolve => {
486 var highest = 'Unranked'
487 pool.getConnection(async function (error, connection) {
488 if (error) { UpdateLogFile(error) } else {
489 var ID = await GetUserID(DiscordID)
490 connection.query("select Highest from ranks where UserID = " + ID, function (error, results, fields) {
491 connection.release()
492 if (error) { UpdateLogFile(error) } else {
493 highest = results[0].Highest
494 UpdateLogFile('SQL Query: Successfully retrieved Highest rank for user ' + DiscordID)
495 }
496 })
497 }
498 })
499 setTimeout(() => {
500 resolve(highest)
501 }, 8000)
502 })
503}
504
505// SQL Query
506// Gets an array of all columns for each user in the queue table
507function GetQueue() {
508 UpdateLogFile('Function Call: GetQueue()')
509 return new Promise(resolve => {
510 var Queue = 0
511 pool.getConnection(function (error, connection) {
512 if (error) { UpdateLogFile(error) } else {
513 connection.query('select * from queue', function (error, results, fields) {
514 connection.release()
515 if (error) { UpdateLogFile(error) } else {
516 if (results.length > 0) {
517 Queue = []
518 results.forEach(function (item) {
519 Queue.push({
520 ID: item.ID,
521 DiscordID: item.DiscordID,
522 Platform: item.Platform,
523 AccountID: item.AccountID
524 })
525 })
526 }
527 UpdateLogFile('SQL Query: Successfully retrieved the queue')
528 }
529 })
530 }
531 })
532 setTimeout(() => {
533 resolve(Queue)
534 }, 5000)
535 })
536}
537
538// Javascript
539// Used to compare a numeric value tied each rank
540// Retrieves a rank based on a given value
541function GetRank(value) {
542 UpdateLogFile('Function Call: GetRank()')
543 var rank = 'Unranked'
544 rankValues.forEach(function (item) {
545 if (item.value === value) {
546 rank = item.rank
547 }
548 })
549 return rank
550}
551
552// Javascript
553// Used to compare a numeric value tied each rank
554// Retrieves a value based on a given rank
555function GetRankValue(rank) {
556 UpdateLogFile('Function Call: GetRankValue()')
557 var Value = 0
558 rankValues.forEach(function (item) {
559 if (item.rank === rank) {
560 Value = item.value
561 }
562 })
563 return Value
564}
565
566// SQL Query
567// Gets an array of all columns for each user in the users table
568function GetUserDetails(DiscordID) {
569 UpdateLogFile('Function Call: GetUserDetails()')
570 return new Promise(resolve => {
571 var details = []
572 pool.getConnection(async function (error, connection) {
573 if (error) { UpdateLogFile(error) } else {
574 var ID = await GetUserID(DiscordID)
575
576 connection.query("select * from users where ID = " + ID + " ORDER BY ID ASC", function (error, results, fields) {
577 connection.release()
578 try {
579 if (error) { UpdateLogFile(error) } else {
580 details.push(results[0].ID)
581 details.push(results[0].DiscordID)
582 details.push(results[0].Platform)
583 details.push(results[0].AccountID)
584 UpdateLogFile('SQL Query: Successfully retrieved all details for user ' + DiscordID)
585 }
586 }
587 catch (e) {
588 console.log("Fehler (" + ID + "):" + e);
589 UpdateLogFile("Fehler (" + ID + "):" + e);
590 }
591 })
592 }
593 })
594 setTimeout(() => {
595 resolve(details)
596 }, 10000)
597 })
598}
599
600// SQL Query
601// Gets the generated ID for a user in the users table
602function GetUserID(DiscordID) {
603 UpdateLogFile("Function Call: GetUserID()")
604 return new Promise(resolve => {
605 var ID = 0
606 pool.getConnection(function (error, connection) {
607 if (error) { UpdateLogFile(error) } else {
608 connection.query("select ID from users where DiscordID = '" + DiscordID + "' ORDER BY ID ASC", function (error, results, fields) {
609 connection.release()
610 if (error) { UpdateLogFile(error) } else {
611 ID = results[0].ID
612 UpdateLogFile('SQL Query: Successfully retrieved ID for user ' + DiscordID)
613 }
614 })
615 }
616 })
617 setTimeout(() => {
618 resolve(ID)
619 }, 5000)
620 })
621}
622
623// SQL Query
624// Gets an array of all ranks for a user in the ranks table
625function GetUserRanks(DiscordID) {
626 UpdateLogFile('Function Call: GetUserRanks()')
627 return new Promise(resolve => {
628 var ranks = []
629 pool.getConnection(async function (error, connection) {
630 if (error) { UpdateLogFile(error) } else {
631 var ID = await GetUserID(DiscordID)
632 connection.query("select * from ranks where UserID = " + ID, function (error, results, fields) {
633 connection.release()
634 if (error) { UpdateLogFile(error) } else {
635 ranks.push(results[0].Standard)
636 ranks.push(results[0].Doubles)
637 ranks.push(results[0].SoloDuel)
638 ranks.push(results[0].SoloStandard)
639 ranks.push(results[0].Rumble)
640 ranks.push(results[0].Dropshot)
641 ranks.push(results[0].Hoops)
642 ranks.push(results[0].SnowDay)
643 UpdateLogFile('SQL Query: Successfully retrieved all ranks for user ' + DiscordID)
644 }
645 })
646 }
647 })
648 setTimeout(() => {
649 resolve(ranks)
650 }, 10000)
651 })
652}
653
654// SQL Query
655// Gets an array of Discord ID's for all users in the users table
656function GetUsers() {
657 UpdateLogFile('Function Call: GetUsers()')
658 return new Promise(resolve => {
659 var users = []
660 pool.getConnection(function (error, connection) {
661 if (error) { UpdateLogFile(error) } else {
662 connection.query('select DiscordID from users', function (error, results, fields) {
663 connection.release()
664 if (error) { UpdateLogFile(error) } else {
665 for (let i = 0; i < results.length; i++) {
666 users.push(results[i].DiscordID)
667 }
668 UpdateLogFile('SQL Query: Successfully retrieved DiscordID for all users')
669 }
670 })
671 }
672 })
673 setTimeout(() => {
674 resolve(users)
675 }, 5000)
676 })
677}
678
679// Javascript
680// If the queue is not empty, either add or update a user to/in the users table
681async function HandleQueue() {
682 UpdateLogFile('Function Call: HandleQueue()')
683 if (!emptyQueue) {
684 handlingQueue = true
685 var queue = await GetQueue()
686 if (queue === 0) {
687 emptyQueue = true
688 handlingQueue = false
689 } else {
690 emptyQueue = false
691 for (let i = 0; i < queue.length; i++) {
692 if (await NewUser(queue[i].DiscordID)) {
693 await AddUser(queue[i].DiscordID, queue[i].Platform, queue[i].AccountID)
694 } else {
695 await EditUser(queue[i].DiscordID, queue[i].Platform, queue[i].AccountID)
696 }
697 await RemoveFromQueue(queue[i].ID)
698 }
699 handlingQueue = false
700 }
701
702 }
703}
704
705// SQL Query
706// Checks to see if a user already exists in the users table
707function NewUser(DiscordID) {
708 UpdateLogFile('Function Call: NewUser()')
709 return new Promise(resolve => {
710 var newUser = true
711 pool.getConnection(function (error, connection) {
712 if (error) { UpdateLogFile(error) } else {
713 connection.query("select * from users where DiscordID = '" + DiscordID + "'", function (error, results, fields) {
714 connection.release()
715 if (error) { UpdateLogFile(error) } else {
716 if (results.length > 0) {
717 newUser = false
718 UpdateLogFile('SQL Query: User ' + DiscordID + ' already exists')
719 } else {
720 UpdateLogFile('SQL Query: User ' + DiscordID + ' does not exist')
721 }
722 }
723 })
724 }
725 })
726 setTimeout(() => {
727 resolve(newUser)
728 }, 5000)
729 })
730}
731
732// SQL Query
733// Removes a user from the queue table
734function RemoveFromQueue(ID) {
735 UpdateLogFile('Function Call: RemoveFromQueue()')
736 return new Promise(resolve => {
737 pool.getConnection(function (error, connection) {
738 if (error) { UpdateLogFile(error) } else {
739 connection.query("delete from queue where ID = " + ID, function (error, results, fields) {
740 connection.release()
741 if (error) { UpdateLogFile(error) }
742 })
743 }
744 })
745 setTimeout(() => {
746 resolve(UpdateLogFile('SQL Query: Successfully removed a user from the queue'))
747 }, 5000)
748 })
749}
750
751// Discord Process
752// Removes a role from a user in the server
753function RemoveRoleFromUser(DiscordID, Role) {
754 UpdateLogFile('Function Call: RemoveRoleFromUser()')
755 return new Promise(resolve => {
756 setTimeout(() => {
757 bot.guilds.get(ServerID).members.get(DiscordID).removeRole(Role.ID)
758 UpdateLogFile('Discord Process: Successfully removed role ' + Role.Role + ' from user ' + DiscordID)
759 }, 2000)
760 })
761}
762
763// Javascript
764// Creates an array with values tied to each rank for use with the "Highest" role
765function SetRankValues() {
766 UpdateLogFile('Function Call: SetRankValues()')
767 for (let i = 0; i < ranks2.length; i++) {
768 rankValues.push({
769 rank: ranks2[i],
770 value: i
771 })
772 }
773}
774
775// Updates a user's "Highest" role in the server
776async function UpdateHighest(DiscordID) {
777 UpdateLogFile('Function Call: UpdateHighest()')
778 var highest = await GetHighest(DiscordID)
779 var highestValue = GetRankValue(highest) // The value of the old highest rank of the user
780 var userRanks = await GetUserRanks(DiscordID)
781 var currentHighest = 0
782 // Get the value of the new highest rank of the user
783 for (let i = 0; i < userRanks.length; i++) {
784 for (let j = rankValues.length - 1; j >= 0; j--) {
785 if (userRanks[i].startsWith(rankValues[j].rank)) {
786 if (rankValues[j].value > currentHighest) {
787 currentHighest = rankValues[j].value
788 }
789 }
790 }
791 }
792 // Get the rank of the new or old highest value
793 if (currentHighest != highestValue) {
794 highest = GetRank(currentHighest)
795 } else {
796 highest = GetRank(highestValue)
797 }
798 let currentRole;
799 try {
800 currentRole = bot.guilds.get(ServerID).roles.find(role => role.name === highest).id
801 let existingRole = bot.guilds.get(ServerID).members.get(DiscordID).roles.has(currentRole)
802
803
804
805 // If the current user does not have the role
806 if (!existingRole) {
807 // Remove all other "Highest" roles the user might have
808 for (let i = 0; i < ranks2.length; i++) {
809 let currentRole = bot.guilds.get(ServerID).roles.find(role => role.name === ranks2[i]).id
810 if (bot.guilds.get(ServerID).members.get(DiscordID).roles.has(currentRole)) {
811 setTimeout(() => {
812 bot.guilds.get(ServerID).members.get(DiscordID).removeRole(currentRole)
813 }, 1000);
814 }
815 }
816 // Add the new "Highest" role to the user
817 let currentRole = bot.guilds.get(ServerID).roles.find(role => role.name === highest).id
818 bot.guilds.get(ServerID).members.get(DiscordID).addRole(currentRole)
819 await AddHighest(DiscordID, highest)
820 }
821 } catch (e) {
822
823 }
824}
825
826// Javascript
827// Updates log.txt with a new value
828function UpdateLogFile(newValue) {
829 var CurrentTime = new Date()
830 var today = CurrentTime.getDate().toString() + '/' + (CurrentTime.getMonth() + 1).toString() + '/' + CurrentTime.getFullYear().toString()
831 var ClockTime = CurrentTime.getHours().toString() + ':' + CurrentTime.getMinutes().toString() + ':' + CurrentTime.getSeconds().toString()
832 var FullTime = today + ' ' + ClockTime + ' >>> '
833 FS.appendFile('log.txt', FullTime + newValue + '\r\n', function (error) {
834 if (error) { console.log(error) }
835 })
836}
837
838// Discord Process
839// Updates all rank roles for a user in the server
840async function UpdateRankRoles(DiscordID) {
841 var userRanks = await GetUserRanks(DiscordID)
842 // Get an array of roles that the user should have
843 var newRoles = []
844 for (let i = 0; i < modes.length; i++) {
845 newRoles.push(modes[i] + ' ' + userRanks[i])
846 }
847 var userRoles = [] // Used for the user's existing roles
848 var tempRanks = [] // Used as a list of roles to ignore
849 ranks2.forEach(function (item) {
850 tempRanks.push(item)
851 })
852 tempRanks.push('@everyone')
853 tempRanks.push('Owner')
854 tempRanks.push('Nadeko')
855 tempRanks.push('Birthday Bot')
856 tempRanks.push('Geburtstagskind ?')
857 tempRanks.push('Moderator')
858 tempRanks.push('VIP (Twitch)')
859 tempRanks.push('Twitch Subscriber')
860 tempRanks.push('Tier 3')
861 tempRanks.push('Tier 2')
862 tempRanks.push('Tier 1')
863 tempRanks.push('YAGPDB.xyz')
864 tempRanks.push('Rocket League')
865 tempRanks.push('Fortnite')
866 tempRanks.push('Osu!')
867 tempRanks.push('DE')
868 tempRanks.push('AT')
869 tempRanks.push('CH')
870 tempRanks.push('Bot')
871 tempRanks.push('CleanChat')
872 tempRanks.push('BotAleksS')
873 tempRanks.push('PatchBot')
874 tempRanks.push('RLTracker by RegiumNova.de')
875 tempRanks.push('BetterTTV')
876 tempRanks.push('Ark')
877 tempRanks.push('F1')
878 tempRanks.push('RL Itemshop')
879
880 // Add a statement like this for any pre-existing role in your server
881 // Get all roles from the user
882 try {
883 //console.log("'"+DiscordID+"' gerade in Benutzung")
884 bot.guilds.get(ServerID).members.get(DiscordID).roles.forEach(function (role, key, map) {
885 if (!tempRanks.includes(role.name)) {
886 userRoles.push({
887 Role: role.name,
888 ID: role.id
889 })
890 }
891 })
892 newRoles.forEach(function (item) {
893 var itemFound = false
894 // Check if user already has this role
895 for (let i = 0; i < userRoles.length; i++) {
896 if (item === userRoles[i].Role) {
897 itemFound = true
898 }
899 }
900 // If not, add the role to the user
901 if (!itemFound) {
902 setTimeout(async function () {
903 await AddRoleToUser(DiscordID, item)
904 }, 1000)
905 }
906 })
907 // Delay 5 seconds
908 setTimeout(function () {
909 userRoles = []
910 // Get all the users roles again since they have been updated
911 bot.guilds.get(ServerID).members.get(DiscordID).roles.forEach(function (role, key, map) {
912 if (!tempRanks.includes(role.name)) {
913 userRoles.push({
914 Role: role.name,
915 ID: role.id
916 })
917 }
918 })
919 userRoles.forEach(function (item) {
920 var itemFound = false
921 // Check if the user has a role he shouldn't have
922 for (let i = 0; i < newRoles.length; i++) {
923 if (item.Role === newRoles[i]) {
924 itemFound = true
925 }
926 }
927 // If he does, delete the role from the user
928 if (!itemFound) {
929 setTimeout(async function () {
930 await RemoveRoleFromUser(DiscordID, item)
931 }, 1000)
932 }
933 })
934 }, 5000)
935 } catch (e) {
936 console.log(e);
937 console.log("'"+DiscordID+"' nicht erkannt")
938 //if(enabled)
939 //delete_user(pool,DiscordID);
940 }
941}
942
943// Javascript
944// Parses the Rocket League Tracker Network to get each competitive rank for a user
945async function UpdateStats(DiscordID) {
946 UpdateLogFile('Function Call: UpdateStats()')
947 // Get all columns from the users table for the user
948 var details = await GetUserDetails(DiscordID)
949 var UserID = details[0]
950 var Platform = details[2]
951 var AccountID = details[3]
952 var temp = []
953 rp(URL + Platform + '/' + AccountID + '/overview')
954 .then(function (html) {
955 let data = [[], [],[]]
956 var tableIndex = 1
957 // Check whether the user has season rewards or not
958 if ($(' .trn-table', html)[tableIndex]) {
959 tableIndex = 1
960 } else {
961 tableIndex = 0
962 }
963 for (let k = 1; k < 18; k += 2) {
964 try {
965 // These are the addresses for each game mode and corresponding rank
966 // It is possible that they could change in the future if the website's structure changes
967
968 let newMode = $(' .trn-table', html)[0].children[3].children[k].children[2].children[0].children[0].data.trim()
969 let newRank = $(' .trn-table', html)[0].children[3].children[k].children[2].children[1].children[0].data.trim()
970 let rating = $(' .trn-table', html)[0].children[3].children[k].children[3].children[0].children[1].children[0].children[0].data.trim()
971
972 data[0].push(newMode)
973 data[1].push(newRank)
974 data[2].push(rating)
975 } catch (error) {
976 UpdateLogFile('Mode or Rank not found for user ' + DiscordID)
977 console.log("Mode or Rank not found for user " + DiscordID)
978 }
979 }
980 return Promise.all(
981 data.map(function (item) {
982 temp.push(item)
983 })
984 )
985 })
986 .then(function () {
987 var tempModes = temp[0]
988 var tempRanks = temp[1]
989 var temprating = temp[2];
990 // remove the "Unranked" (Casual) category
991 tempModes.splice(0, 1)
992 tempRanks.splice(0, 1)
993 for (let j = 0; j < tempRanks.length; j++) {
994 // Format each one appropriately
995 tempModes[j] = tempModes[j].replace('Ranked ', '')
996 tempModes[j] = tempModes[j].replace(' 1v1', '')
997 tempModes[j] = tempModes[j].replace(' 2v2', '')
998 tempModes[j] = tempModes[j].replace(' 3v3', '')
999 tempModes[j] = tempModes[j].replace('Duel', 'Solo Duel')
1000 tempModes[j] = tempModes[j].replace('Snowday', 'Snow Day')
1001 tempModes[j] = tempModes[j].replace(' ', '')
1002 temprating[j] = temprating[j].replace(',','')
1003 tempRanks[j] = tempRanks[j].slice(0, tempRanks[j].indexOf('\n'))
1004 // Add the new stat to ranks table for the user
1005 AddUserStat(UserID, tempModes[j], tempRanks[j], temprating[j])
1006 }
1007 })
1008 .catch(function (error) {
1009 UpdateLogFile(error)
1010 })
1011}
1012
1013// Javascript
1014// Gets an array of Discord ID's from the users table and calls UpdateStats() for each
1015async function UpdateUsers() {
1016 updatingRanks = true
1017 var users = await GetUsers()
1018 for (let i = 0; i < users.length; i++) {
1019 await UpdateStats(users[i])
1020 }
1021 updatingRanks = false
1022}
1023
1024// Discord Process
1025// Checks if a user has a role called "Admin"
1026function UserIsAdmin(message) {
1027 UpdateLogFile('Function Call: UserIsAdmin()')
1028 var AdminRole = message.guild.roles.find(role => role.name === 'Owner')
1029 if (AdminRole) {
1030 return message.member.roles.has(AdminRole.id)
1031 } else {
1032 return false
1033 }
1034}
1035
1036// Discord Process
1037// Checks if a user is mentioned in the command message
1038function UserMentioned(message) {
1039 UpdateLogFile('Function Call: UserMentioned()')
1040 return message.mentions.members.first()
1041}
1042
1043// Javascript
1044// Creates log.txt if it doesn't already exist
1045function VerifyLogFile() {
1046 FS.exists('log.txt', function (exists) {
1047 if (exists) {
1048 UpdateLogFile('log.txt already exists')
1049 } else {
1050 var log = FS.createWriteStream('log.txt')
1051 log.end()
1052 }
1053 })
1054}
1055
1056function delete_user(pool, DiscordID) {
1057 if (enabled) {
1058 pool.getConnection(function (error, connection) {
1059 if (error) { UpdateLogFile(error) } else {
1060 connection.query("SELECT * FROM users WHERE DiscordID = '" + DiscordID + "'", function (error, results, fields) {
1061 t = results[0].leavecheck;
1062 if (t != 3) {
1063 t++;
1064
1065 //DELETE FROM `tgfcptdk_tracker`.`users` WHERE `ID`=114;
1066 connection.query("UPDATE users SET leavecheck = '" + t + "' WHERE DiscordID =" + DiscordID, function (error, results, fields) {
1067 console.log("Discord ID: " + DiscordID + " wurde auf " + t + " gesetzt")
1068 UpdateLogFile("Discord ID: " + DiscordID + " wurde auf " + t + " gesetzt")
1069 connection.release()
1070 if (error) { UpdateLogFile(error) }
1071
1072 })
1073 } else {
1074 connection.query("DELETE FROM users WHERE DiscordID=" + DiscordID, function (error, results, fields) {
1075 connection.release()
1076 if (error) { UpdateLogFile(error) }
1077 console.log("Discord ID: " + DiscordID + " hat den Discord Verlassen und wurde Gelöscht")
1078 UpdateLogFile("Discord ID: " + DiscordID + " hat den Discord Verlassen und wurde Gelöscht")
1079
1080 })
1081 }
1082 })
1083 }
1084 })
1085 } else {
1086
1087 console.log("Bot deaktiviert: !rlenable nutzen um bot zu reaktivieren");
1088 UpdateLogFile("Bot deaktiviert: !rlenable nutzen um bot zu reaktivieren");
1089
1090 }
1091}