const Crypto = require('crypto-js'), Moment = require('moment'), Colors = require("./colors"), ColorsJS = require('colors'); module.exports = class Util { constructor(bot) { this.ESMBot = bot; this.regex = { serverID: { base: /[^\s]+_[^\s]+/i, only: /^[^\s]+_[^\s]+$/i }, broadcast: { base: /(?:[^\s]+_[^\s]+)|all|test/i, only: /(?:^[^\s]+_[^\s]+$)|^all$|^test$/i }, communityID: { base: /[^\s]+/i, only: /^[^\s]+$/i }, steamUID: { base: /\d{17}/i, only: /^\d{17}$/i }, target: { base: /\d{17}|<@!?\d+>/i, only: /^\d{17}$|^<@!?\d+>$/i }, targetAcceptDeny: { base: /\d{17}|<@!?\d+>|accept|decline/i, only: /^\d{17}$|^<@!?\d+>$|^accept$|^decline$/i }, territoryID: { base: /\w+/i, only: /^\w+$/i }, discordTag: { base: /<@!?\d+>/i, only: /^<@!?\d+>$/i }, discordID: { base: /\d{18}/i, only: /^\d{18}$/i }, targetOrTerritory: { base: /\d{17}|<@!?\d+>|\w+/i, only: /^\d{17}|<@!?\d+>|\w+$/i }, acceptDecline: { base: /accept|decline/i, only: /^accept$|^decline$/i } }; this.embed = { EMPTY_SPACE: "\u200B", TITLE_LENGTH_MAX: 256, DESCRIPTION_LENGTH_MAX: 2048, FIELD_NAME_LENGTH_MAX: 256, FIELD_VALUE_LENGTH_MAX: 1024 }; } ////////////////////////////////////////////////////// getFlagPath(flagPath) { let defaultFlag = "./flags/flag_white_co.jpg"; if (flagPath === "") { return defaultFlag; } let flagName = /(flag_.*)\.paa/i.exec(flagPath); if (flagName == null) { return defaultFlag; } return `./flags/${flagName[1]}.jpg`; } ////////////////////////////////////////////////////// stringCombine(array) { let output = ""; if (array.length === 0) return ""; if (Array.isArray(array[0])) { array = array[0]; } for (let i = 0; i < array.length; i++) { output += `\n${array[i]}`; } return output; } ////////////////////////////////////////////////////// parseTime(time) { const methods = [{ name: 'd', count: 86400 }, { name: 'h', count: 3600 }, { name: 'm', count: 60 }, { name: 's', count: 1 } ] const timeStr = [Math.floor(time / methods[0].count).toString() + methods[0].name]; for (let i = 0; i < 3; i++) { timeStr.push(Math.floor(time % methods[i].count / methods[i + 1].count).toString() + methods[i + 1].name) } return timeStr.filter(g => !g.startsWith('0')).join(' ') } ////////////////////////////////////////////////////// convertTime(timeString) { let time = Moment.utc(timeString); return time.isValid() ? time : null; } ////////////////////////////////////////////////////// addDays(date, days) { return date.add(days, "d"); } ////////////////////////////////////////////////////// isEmpty(obj, requiredAttr = []) { if (obj == null) return true; if (Array.isArray(obj)) { return obj.length === 0; } switch (typeof (obj)) { case "object": if (this.getKeys(obj).length === 0) return true; if (requiredAttr.length > 0) { for (let attr of requiredAttr) { if (obj.hasOwnProperty(attr)) { if (this.isEmpty(obj[attr])) return true; } } } return this.getKeys(obj).length === 0; case "string": return obj.length === 0; default: return false; } } ////////////////////////////////////////////////////// isNull(thing) { return thing == null; } ////////////////////////////////////////////////////// isObject(thing) { return typeof (thing) === "object"; } ////////////////////////////////////////////////////// isArray(thing) { return Array.isArray(thing); } ////////////////////////////////////////////////////// isString(thing) { return typeof (thing) === "string"; } ////////////////////////////////////////////////////// encrypt(string) { if (typeof (string) === "object") { string = JSON.stringify(string); } return Crypto.AES.encrypt(string, this.ESMBot.config.ENCRYPTION_TOKEN).toString(); } ////////////////////////////////////////////////////// decrypt(token) { try { if (token === "") throw null; token = Crypto.AES.decrypt(token, this.ESMBot.config.ENCRYPTION_TOKEN).toString(Crypto.enc.Utf8); if (token == null || token === "") throw null; return token } catch (err) { return null; } } ////////////////////////////////////////////////////// getKeys(obj) { return Object.keys(obj); } ////////////////////////////////////////////////////// titleize(string) { return string.charAt(0).toUpperCase() + string.slice(1); } ////////////////////////////////////////////////////// generateKey(length, useLowerCase = true, useUpperCase = true, useNumbers = true, useSpecial = true, useHex = false) { const lowerCase = 'abcdefghijklmnopqrstuvwxyz'; const upperCase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; const numbers = '1234567890'; const special = '`~!@#$%^&*()-=_+[]{}|;\':",./<>?'; const hex = '123456789ABCDEF'; let chars = ''; let key = ''; if (useLowerCase) chars += lowerCase; if (useUpperCase) chars += upperCase; if (useNumbers) chars += numbers; if (useSpecial) chars += special; if (useHex) chars += hex; for (let i = 0; i < length; i++) { key += chars[Math.floor(Math.random() * chars.length)]; } return key; } ////////////////////////////////////////////////////// sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } ////////////////////////////////////////////////////// isGuildAvailable(guild) { if (guild == null) return false; return guild.available; } ////////////////////////////////////////////////////// getCommunityID(id) { let match = /^([^\s_<>]+)_[^\s<>]+$/i.exec(id); if (match != null) { id = match[1]; } return id; } ////////////////////////////////////////////////////// arrayToString(array) { if (this.isEmpty(array)) return "[]"; if (!Array.isArray(array)) return "[]"; let output = "["; for (let item of array) { if (typeof item === "string") { output += `"${item}",`; } else if (Array.isArray(item)) { output += `${this.arrayToString(item)},`; } else { output += `${item},`; } } output = output.slice(0, -1); return output + "]"; } ////////////////////////////////////////////////////// arrayToStringPretty(array, delim = ", ", markup = "") { if (this.isEmpty(array)) return ""; let output = ""; for (let item of array) { output += `${markup}${item}${markup}${delim}`; } output = output.slice(0, -delim.length); return output; } ////////////////////////////////////////////////////// objectArrayToString(array) { if (this.isEmpty(array)) return ""; let output = ""; if (array.length === 1) { output = `${this.objectToString(array[0])}`; } else { for (let i = 0; i < array.length; i++) { let item = array[i]; output += `--------- index ${i} ---------\n${this.objectToString(item)}\n\n`; } } return output; } ////////////////////////////////////////////////////// objectToStringFormatted(object) { if (this.isEmpty(object)) return ""; let output = ""; for (let attribute in object) { output += `**${this.titleize(attribute)}**: ${ typeof(object[attribute]) === "object" ? JSON.stringify(object[attribute]) : object[attribute]}\n`; } return output; } ////////////////////////////////////////////////////// objectToString(object) { if (this.isEmpty(object)) return ""; let output = ""; for (let attribute in object) { output += `${attribute}: ${ typeof(object[attribute]) === "object" ? JSON.stringify(object[attribute]) : object[attribute]}\n`; } return output; } ////////////////////////////////////////////////////// hasOwnProperties(object, properties, requireAll = false) { if (this.isEmpty(object)) return false; let hasAllProperties = false; let keys = this.getKeys(object); for (let property of properties) { if (keys.includes(property) && !requireAll) { return true; } hasAllProperties = keys.includes(property); } return hasAllProperties; } ////////////////////////////////////////////////////// selectRandom(objOrArray) { if (typeof objOrArray === "object") { let keys = this.getKeys(objOrArray); return objOrArray[keys[keys.length * Math.random() << 0]]; } else if (Array.isArray(objOrArray)) { return objOrArray[Math.floor(Math.random() * objOrArray.length)]; } return null; } ////////////////////////////////////////////////////// isTypeOf(object, className) { return object.constructor.name === className; } ////////////////////////////////////////////////////// minifyCode(code) { code = code.replace(/\s*\;\s*/g, ";"); code = code.replace(/\s*\:\s*/g, ":"); code = code.replace(/\s*\,\s*/g, ","); code = code.replace(/\s*\[\s*/g, "["); code = code.replace(/\s*\]\s*/g, "]"); code = code.replace(/\s*\(\s*/g, "("); code = code.replace(/\s*\)\s*/g, ")"); code = code.replace(/\s*\-\s*/g, "-"); code = code.replace(/\s*\+\s*/g, "+"); code = code.replace(/\s*\/\s*/g, "/"); code = code.replace(/\s*\*\s*/g, "*"); code = code.replace(/\s*\%\s*/g, "%"); code = code.replace(/\s*\=\s*/g, "="); code = code.replace(/\s*\!\s*/g, "!"); code = code.replace(/\s*\>\s*/g, ">"); code = code.replace(/\s*\<\s*/g, "<"); code = code.replace(/\s*\>\>\s*/g, ">>"); code = code.replace(/\s*\&\&\s*/g, "&&"); code = code.replace(/\s*\|\|\s*/g, "||"); code = code.replace(/\s*\}\s*/g, "}"); code = code.replace(/\s*\{\s*/g, "{"); code = code.replace(/\s+/g, " "); code = code.replace(/\n+/g, ""); code = code.replace(/\r+/g, ""); code = code.replace(/\t+/g, ""); return code; } convertArmaNumber(number) { let converter = new Intl.NumberFormat('en-US', { minimumFractionDigits: 0 }); return converter.format(+number); } tryParseJSON(json) { try { return JSON.parse(json); } catch (err) { return null; } } hasOwnPropertyTree(object, ...properties) { // Make sure the object actually has stuff if (this.isEmpty(object)) return false; // We only have one, just use the simple method if (_.size(properties) === 1) { return object.hasOwnProperty(properties[0]); } else { let valid = true; let currentObject = object; // Loop through each property passed, remembering the previous object so we can go through the tree. _.each(properties, property => { if (currentObject.hasOwnProperty(property)) { currentObject = currentObject[property]; } else { return valid = false; } }); return valid; } } };