├── .env.example ├── .gitignore ├── LICENSE ├── README.md ├── bot ├── base │ ├── BotClass.js │ ├── Command.js │ ├── Event.js │ ├── Level.js │ └── Logger.js ├── commands │ ├── System │ │ ├── eval.js │ │ ├── execute.js │ │ ├── reload.js │ │ └── restart.js │ └── Utility │ │ ├── bump.js │ │ ├── help.js │ │ ├── info.js │ │ ├── invite.js │ │ ├── page.js │ │ ├── ping.js │ │ └── vanityurl.js ├── database │ ├── Database.js │ └── classes │ │ ├── index.js │ │ └── reboot.js └── events │ ├── guildCreate.js │ ├── guildDelete.js │ ├── message.js │ ├── messageUpdate.js │ └── ready.js ├── dynamic ├── blocks │ ├── footer.ejs │ ├── guildtop.ejs │ ├── header.ejs │ └── navbar.ejs ├── errors │ ├── 403.ejs │ ├── 404.ejs │ └── express.ejs ├── index.ejs ├── markdown.ejs ├── me │ ├── add.ejs │ ├── admin.ejs │ ├── servers.ejs │ └── settings.ejs ├── partners.ejs ├── privacy.ejs ├── search │ ├── alltags.ejs │ ├── category.ejs │ ├── list.ejs │ └── search.ejs ├── servers │ ├── 404.ejs │ ├── bump.ejs │ ├── edit.ejs │ ├── join.ejs │ └── view.ejs └── terms.ejs ├── index.js ├── models ├── reboot.js └── servers.js ├── package-lock.json ├── package.json ├── public ├── arc-sw.js ├── prismjs │ ├── prism.css │ └── prism.js └── style │ └── style.css ├── routes ├── apiroutes.js ├── authroutes.js ├── index.js ├── meroutes.js ├── serversroutes.js ├── tagroutes.js └── vanity.js └── structures ├── app.js ├── discordApi.js ├── fileWalk.js └── middleware.js /.env.example: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # 3 | # Void Servers Global Variables 4 | # Do not touch unless you know what you're doing... 5 | # 6 | #=========================================================================== 7 | # Void Servers created by DanPlayz and AshMW 8 | # https://ashmw.com | https://danplayz.com 9 | #=========================================================================== 10 | # 11 | ############################################################################ 12 | 13 | ############################################################################ 14 | # Guild Variables 15 | ############################################################################ 16 | # Void Guild | Main Guild Invite 17 | GUILD_INVITE=https://discord.gg/huhP4Vs 18 | 19 | # Void Guild | Main Server ID 20 | GUILD_ID=733135938347073576 21 | 22 | # Void Guild | Join/Leave Log Channel ID 23 | GUILD_LOG= 24 | 25 | ############################################################################ 26 | # System Variables 27 | ############################################################################ 28 | # Void System | MongoDB URL 29 | MONGO_DB_URL= 30 | 31 | # Void System | Domain 32 | DOMAIN=https://voidlist.xyz 33 | 34 | # Void System | Vanity Domain 35 | VANITY_DOMAIN=https://di.scord.xyz 36 | 37 | # Void System | Port 38 | PORT=80 39 | 40 | ############################################################################ 41 | # Void Servers Variables 42 | ############################################################################ 43 | # Void Servers | ID 44 | CLIENT_ID= 45 | 46 | # Void Servers | Secret 47 | CLIENT_SECRET= 48 | 49 | # Void Servers | Token 50 | DISCORD_TOKEN= 51 | 52 | # Void Servers | Prefix 53 | PREFIX=vs. 54 | 55 | ############################################################################ 56 | # Permission Variables 57 | ############################################################################ 58 | # Void Perms | Admins (Seperated by spaces) 59 | ADMIN_USERS="209796601357533184 229285505693515776 606279329844035594" 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | .env -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](http://discord.mx/NZFb8GigkP.png) 2 | # Void Server List 3 | The code for https://voidlist.xyz a Node.JS Discord server list. 4 | 5 | --- 6 | 7 | ### Setting up: 8 | 1. Fill in all the unset variables in the `.env.example` file. 9 | 2. Rename the file to `.env` 10 | 3. Startup the server! 11 | 12 | --- 13 | 14 | ### Notes: 15 | We encourage you to use this as a starting point instead of just changing the name and running it. 16 | 17 | We kindly ask you to add `Programmed by DanPlayz and designed by AshMW` somewhere visible if you decide to clone this! 18 | 19 | 20 | -------------------------------------------------------------------------------- /bot/base/BotClass.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const klaw = require("klaw"); 3 | const path = require("path"); 4 | const { promisify } = require('util'); 5 | const { Client, Collection } = require("discord.js"); 6 | const Database = require('@bot/database/Database.js'); 7 | 8 | class VoidBot extends Client { 9 | constructor(options) { 10 | super(options); 11 | 12 | this.perms = require('@bot/base/Level'); // Danno's PermLevel Methods. 13 | this.database = new Database(this); 14 | this.logger = require('@bot/base/Logger'); 15 | 16 | // Create the Collections 17 | this.commands = new Collection(); 18 | this.aliases = new Collection(); 19 | this.events = new Collection(); 20 | 21 | // Debug option 22 | this.DEBUG = false; 23 | 24 | // Load Commands/Events 25 | this.loadCommands('./bot/commands'); 26 | this.loadEvents('./bot/events'); 27 | 28 | // Basically just an async shortcut to using a setTimeout. Nothing fancy! 29 | this.wait = promisify(setTimeout); // Used in ready event 30 | } 31 | 32 | /** 33 | * PERMISSION LEVEL FUNCTION 34 | * 35 | * This is a very basic permission system for commands which uses "levels" 36 | * "spaces" are intentionally left black so you can add them if you want. 37 | * NEVER GIVE ANYONE BUT OWNER THE LEVEL 10! By default this can run any 38 | * command including the VERY DANGEROUS `eval` command! 39 | * @param {*} message The Message 40 | * @returns {number} 41 | */ 42 | permLevel(message) { 43 | let permlvl = 0; 44 | 45 | const permOrder = this.perms.slice(0).sort((p, c) => p.level < c.level ? 1 : -1); 46 | 47 | while (permOrder.length) { 48 | const currentLevel = permOrder.shift(); 49 | if (message.guild && currentLevel.guildOnly) continue; 50 | if (currentLevel.check(message)) { 51 | permlvl = currentLevel.level; 52 | break; 53 | } 54 | } 55 | return permlvl; 56 | } 57 | 58 | getPerm(member) { 59 | let permlvl = 0; 60 | 61 | const permOrder = this.perms.slice(0).sort((p, c) => p.level < c.level ? 1 : -1); 62 | 63 | while (permOrder.length) { 64 | const currentLevel = permOrder.shift(); 65 | if (member.guild && currentLevel.guildOnly) continue; 66 | if (currentLevel.checkMember(member)) { 67 | permlvl = currentLevel.level; 68 | break; 69 | } 70 | } 71 | return permlvl; 72 | } 73 | 74 | randomNum(min, max) { 75 | min = Math.ceil(min); 76 | max = Math.floor(max); 77 | return Math.floor(Math.random() * (max - min + 1)) + min; 78 | } 79 | 80 | /** 81 | * Loads the commands folder. 82 | * 83 | * @param {*} folder the relative path to the commands folder, i suggest keeping it in the default location 'data/commands'. 84 | */ 85 | loadCommands(folder) { 86 | klaw(folder).on('data', (file) => { 87 | const commandFile = path.parse(file.path); 88 | if (!commandFile.ext || commandFile.ext !== '.js') return; 89 | 90 | const response = this.loadCommand(commandFile.dir, `${commandFile.name}${commandFile.ext}`); 91 | 92 | if (response) this.logger.log(response, "error"); 93 | }); 94 | } 95 | 96 | 97 | /** 98 | * LOAD COMMAND 99 | * 100 | * Used to simplify loading commands from multiple locations 101 | * @param {String} cmdPath 102 | * @param {String} cmdName 103 | */ 104 | loadCommand(cmdPath, cmdName) { 105 | try { 106 | const props = new (require(path.resolve(cmdPath, cmdName)))(this); 107 | 108 | if (!props.conf.enabled) return; 109 | 110 | props.conf.location = cmdPath; 111 | props.conf.fileName = cmdName; 112 | 113 | if (props.init) { 114 | props.init(this); 115 | } 116 | 117 | this.commands.set(props.help.name, props); 118 | 119 | props.conf.aliases.forEach((alias) => { 120 | this.aliases.set(alias, props.help.name); 121 | }); 122 | 123 | if (this.DEBUG === true) this.logger.log(`${cmdName} Loaded`, 'debug'); 124 | return false; 125 | } catch (error) { 126 | return `Unable to load command ${cmdName}: ${error.message}`; 127 | } 128 | } 129 | 130 | /** 131 | * UNLOAD COMMAND 132 | * 133 | * Used to simplify unloads commands from multiple locations 134 | * @param {String} cmdPath 135 | * @param {String} cmdName 136 | */ 137 | async unloadCommand(cmdPath, cmdName) { 138 | let command; 139 | if (this.commands.has(cmdName)) { 140 | command = this.commands.get(cmdName); 141 | } else if (this.aliases.has(cmdName)) { 142 | command = this.commands.get(this.aliases.get(cmdName)); 143 | } else { 144 | return `The command '${cmdName}' doesn't exist, it's not an alias either.`; 145 | } 146 | 147 | if (command.shutdown) { 148 | await command.shutdown(this); 149 | } 150 | 151 | delete require.cache[require.resolve(path.resolve(cmdPath, command.conf.fileName))]; 152 | return false; 153 | } 154 | 155 | /** 156 | * Loads the events folder. 157 | * 158 | * @param {*} folder the relative path to the events folder, i suggest keeping it in the default location 'data/events'. 159 | */ 160 | loadEvents(folder) { 161 | klaw(folder).on('data', (file) => { 162 | const eventFile = path.parse(file.path); 163 | if (!eventFile.ext || eventFile.ext !== '.js') return; 164 | 165 | const response = this.loadEvent(eventFile.dir, `${eventFile.name}${eventFile.ext}`); 166 | 167 | if (response) this.logger.log(response, "error"); 168 | }); 169 | } 170 | 171 | /** 172 | * LOAD EVENT 173 | * 174 | * Used to simplify loading events from multiple locations 175 | * @param {String} evtPath 176 | * @param {String} evtName 177 | */ 178 | loadEvent(evtPath, evtName) { 179 | try { 180 | const props = new (require(path.resolve(evtPath, evtName)))(this); 181 | if (props.conf.enabled === false) return; 182 | props.conf.location = evtPath; 183 | props.conf.fileName = evtName; 184 | if (props.init) { 185 | props.init(this); 186 | } 187 | 188 | this.events.set(props.conf.name, props); 189 | 190 | this.on(props.conf.name, (...args) => props.run(this, ...args)); 191 | 192 | if (this.DEBUG === true) this.logger.log(`${evtName} Loaded`, 'debug'); 193 | return false; 194 | } catch (error) { 195 | return `Unable to load event ${evtName}: ${error.message}`; 196 | } 197 | } 198 | 199 | /** 200 | * UNLOAD EVENT 201 | * 202 | * Used to simplify unloads events from multiple locations 203 | * @param {String} evtPath 204 | * @param {String} evtName 205 | */ 206 | async unloadEvent(evtPath, evtName) { 207 | let event; 208 | if (this.events.has(evtName)) { 209 | event = this.events.get(evtName); 210 | } else { 211 | return `The event '${evtName}' doesn't exist`; 212 | } 213 | 214 | if (event.shutdown) { 215 | await event.shutdown(this); 216 | } 217 | 218 | delete require.cache[require.resolve(path.resolve(evtPath, event.conf.fileName))]; 219 | return false; 220 | } 221 | 222 | reloadEvent(evtPath, evtName) { 223 | try { 224 | const props = new (require(path.resolve(evtPath, evtName)))(this); 225 | 226 | if (props.conf.enabled === false) return; 227 | 228 | props.conf.location = evtPath; 229 | props.conf.fileName = evtName; 230 | 231 | if (props.init) { 232 | props.init(this); 233 | } 234 | 235 | this.events.set(props.conf.name, props); 236 | 237 | if (this.DEBUG === true) this.logger.log(`${evtName} Loaded`, 'debug'); 238 | return false; 239 | } catch (error) { 240 | return `Unable to load event ${evtName}: ${error.message}`; 241 | } 242 | } 243 | } 244 | 245 | module.exports = VoidBot; 246 | -------------------------------------------------------------------------------- /bot/base/Command.js: -------------------------------------------------------------------------------- 1 | class Command { 2 | 3 | constructor (client, { 4 | name = null, 5 | description = "No description provided.", 6 | category = "Uncategorized", 7 | usage = "No usage provided.", 8 | enabled = true, 9 | guildOnly = false, 10 | aliases = [], 11 | permLevel = "User", 12 | cooldown = 0, 13 | }) { 14 | this.client = client; 15 | this.conf = { enabled, guildOnly, aliases, permLevel, cooldown }; 16 | this.help = { name, description, category, usage }; 17 | } 18 | } 19 | module.exports = Command; 20 | -------------------------------------------------------------------------------- /bot/base/Event.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * This class creates the command properties to be used 4 | */ 5 | class Event { 6 | /** 7 | * Available properties for the command 8 | * @param {Object} client - Bots client object 9 | * @param {String} name - Name of the command 10 | * @param {String} description - Description of the command 11 | * @param {Boolean} enabled - Is command enabled 12 | */ 13 | constructor(client, { 14 | name = 'not provided', 15 | enabled = false, 16 | }) { 17 | this.client = client; 18 | this.conf = { name, enabled }; 19 | } 20 | } 21 | module.exports = Event; 22 | -------------------------------------------------------------------------------- /bot/base/Level.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 'use strict'; 3 | 4 | /** 5 | * PERMISSION LEVELS 6 | ** 0 = non-roled users 7 | ** 1 = Trial Moderator 8 | ** 2 = Moderator 9 | ** 3 = Bot Approver 10 | ** 4 = Trial Manager 11 | ** 5 = Manager 12 | ** 6 = Blank 13 | ** 7 = Blank 14 | ** 8 = Blank 15 | ** 9 = Site Admin 16 | ** 10 = Bot Owner 17 | */ 18 | const permLevels = [ 19 | // Level 0 ~ Everyone has access 20 | { 21 | level: 0, 22 | name: 'User', 23 | check: () => true, 24 | checkMember: () => true, 25 | }, 26 | 27 | // Level 1 ~ Trial Moderator or higher has access 28 | { 29 | level: 1, 30 | name: 'Trial Moderator', 31 | check: (message) => { 32 | const role = message.client.guilds.cache.get(process.env.GUILD_ID).roles.cache.get(process.env.TRIALMODERATOR_ROLE); 33 | if (!role) return false; 34 | try { 35 | const trialmodRole = message.client.guilds.cache.get(process.env.GUILD_ID).roles.cache.get(process.env.TRIALMODERATOR_ROLE); 36 | return trialmodRole && message.client.guilds.cache.get(process.env.GUILD_ID).members.cache.get(message.member.id).roles.cache.has(trialmodRole.id); 37 | } catch (e) { 38 | return false; 39 | } 40 | }, 41 | checkMember: (member) => { 42 | const role = member.client.guilds.cache.get(process.env.GUILD_ID).roles.cache.get(process.env.TRIALMODERATOR_ROLE); 43 | if (!role) return false; 44 | try { 45 | const trialmodRole = member.client.guilds.cache.get(process.env.GUILD_ID).roles.cache.get(process.env.TRIALMODERATOR_ROLE); 46 | return trialmodRole && member.client.guilds.cache.get(process.env.GUILD_ID).members.cache.get(member.id).roles.cache.has(trialmodRole.id); 47 | } catch (e) { 48 | return false; 49 | } 50 | }, 51 | }, 52 | 53 | // Level 2 ~ Moderator or higher has access 54 | { 55 | level: 2, 56 | name: 'Moderator', 57 | check: (message) => { 58 | const role = message.client.guilds.cache.get(process.env.GUILD_ID).roles.cache.get(process.env.MODERATOR_ROLE); 59 | if (!role) return false; 60 | try { 61 | const modRole = message.client.guilds.cache.get(process.env.GUILD_ID).roles.cache.get(process.env.MODERATOR_ROLE); 62 | return modRole && message.client.guilds.cache.get(process.env.GUILD_ID).members.cache.get(message.member.id).roles.cache.has(modRole.id); 63 | } catch (e) { 64 | return false; 65 | } 66 | }, 67 | checkMember: (member) => { 68 | const role = member.client.guilds.cache.get(process.env.GUILD_ID).roles.cache.get(process.env.MODERATOR_ROLE); 69 | if (!role) return false; 70 | try { 71 | const modRole = member.client.guilds.cache.get(process.env.GUILD_ID).roles.cache.get(process.env.MODERATOR_ROLE); 72 | return modRole && member.client.guilds.cache.get(process.env.GUILD_ID).members.cache.get(member.id).roles.cache.has(modRole.id); 73 | } catch (e) { 74 | return false; 75 | } 76 | }, 77 | }, 78 | 79 | // Level 10 ~ Site Admin or higher has access 80 | { 81 | level: 10, 82 | name: 'Site Admin', 83 | check: (message) => process.env.ADMIN_USERS.split(' ').includes(message.author.id), 84 | checkMember: (member) => process.env.ADMIN_USERS.split(' ').includes(member.id), 85 | }, 86 | ]; 87 | 88 | module.exports = permLevels; 89 | -------------------------------------------------------------------------------- /bot/base/Logger.js: -------------------------------------------------------------------------------- 1 | /* 2 | Logger class for easy and aesthetically pleasing console logging 3 | */ 4 | const colors = require("colors"); 5 | const moment = require("moment"); 6 | 7 | class Logger { 8 | static log (content, type = "log") { 9 | //return console.log(content); // To remove color. 10 | const timestamp = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]:`; 11 | switch (type) { 12 | case "log": { 13 | return console.log(`${timestamp} ${colors.bgBlue(type.toUpperCase())} ${content} `); 14 | } 15 | case "warn": { 16 | return console.log(`${timestamp} ${colors.black.bgYellow(type.toUpperCase())} ${content} `); 17 | } 18 | case "error": { 19 | return console.log(`${timestamp} ${colors.bgRed(type.toUpperCase())} ${content} `); 20 | } 21 | case "unauthorized": { 22 | return console.log(`${timestamp} ${colors.bgRed(type.toUpperCase())} ${content} `); 23 | } 24 | case "debug": { 25 | return console.log(`${timestamp} ${colors.green(type.toUpperCase())} ${content} `); 26 | } 27 | case "cmd": { 28 | return console.log(`${timestamp} ${colors.black.bgWhite(type.toUpperCase())} ${content}`); 29 | } 30 | case "ready": { 31 | return console.log(`${timestamp} ${colors.black.bgGreen(type.toUpperCase())} ${content}`); 32 | } 33 | default: throw new TypeError("Logger type must be either warn, debug, log, ready, cmd or error."); 34 | } 35 | } 36 | } 37 | module.exports = Logger; -------------------------------------------------------------------------------- /bot/commands/System/eval.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Command = require("@bot/base/Command.js"); 3 | const { inspect } = require('util'); 4 | 5 | class Eval extends Command { 6 | constructor (client) { 7 | super(client, { 8 | name: "eval", 9 | description: "Evaluates arbitrary Javascript.", 10 | category: "System", 11 | usage: "", 12 | aliases: ["evaluate"], 13 | permLevel: "Site Admin", 14 | guildOnly: true, 15 | }); 16 | } 17 | 18 | async run (client, message, args, MessageEmbed) { 19 | const { member, author, channel, guild } = message; 20 | const embed = new MessageEmbed() 21 | .setFooter(message.author.username, message.author.avatarURL()) 22 | const query = args.join(' ') 23 | if (query) { 24 | const code = (lang, code) => (`\`\`\`${lang}\n${String(code).slice(0, 1000) + (code.length >= 1000 ? '...' : '')}\n\`\`\``).replace(client.token,"Really...? I'm not going to give you my token...") 25 | try { 26 | const evald = eval(query) 27 | const res = (typeof evald === 'string' ? evald : inspect(evald, { depth: 0 })) 28 | embed.addField('Result', code('js', res)) 29 | .addField('Type', code('css', typeof evald === 'undefined' ? 'Unknown' : typeof evald)) 30 | .setColor('#8fff8d') 31 | } catch (err) { 32 | embed.addField('Error', code('js', err)) 33 | .setColor('#ff5d5d') 34 | } finally { 35 | message.channel.send(embed).catch(err => { 36 | message.channel.send(`There was an error while displaying the eval result! ${err.message}`) 37 | }) 38 | } 39 | } else { 40 | message.channel.send('Attempting to evaluate nothing.....') 41 | message.channel.send('I got nothing...') 42 | message.channel.send('Maybe... Yah know... Try telling me something to evaluate next time?') 43 | } 44 | } 45 | } 46 | 47 | module.exports = Eval; 48 | -------------------------------------------------------------------------------- /bot/commands/System/execute.js: -------------------------------------------------------------------------------- 1 | const Command = require("@bot/base/Command.js"); 2 | 3 | class ExecuteCMD extends Command { 4 | constructor (client) { 5 | super(client, { 6 | name: "execute", 7 | description: "Execute a console command. (Command Line Commands)", 8 | category: "System", 9 | usage: "", 10 | aliases: ['exec'], 11 | permLevel: "Site Admin", 12 | guildOnly: true, 13 | }); 14 | } 15 | 16 | async run (client, message, args, MessageEmbed) { 17 | if(!args.join(' ')) return message.reply('Please input a console command.'); 18 | let result = require('child_process').execSync(args.join(' ')).toString(); 19 | const e = new MessageEmbed().addField('Result', `\`\`\`js\n${result.slice(0, 2000)}\`\`\``).setFooter(message.author.username, message.author.avatarURL()).setColor('GREEN'); 20 | message.channel.send(e); 21 | } 22 | } 23 | 24 | module.exports = ExecuteCMD; -------------------------------------------------------------------------------- /bot/commands/System/reload.js: -------------------------------------------------------------------------------- 1 | const Command = require("@bot/base/Command.js"); 2 | 3 | class Reload extends Command { 4 | constructor (client) { 5 | super(client, { 6 | name: "reload", 7 | description: "Reloads a command that has been modified.", 8 | category: "System", 9 | usage: "[command]", 10 | aliases: ['r', 'rl'], 11 | permLevel: "Site Admin", 12 | guildOnly: true, 13 | }); 14 | } 15 | 16 | async run (client, message, args, MessageEmbed) { // eslint-disable-line no-unused-vars 17 | let em = new MessageEmbed(); 18 | if (!args || args.length < 1) return em.setDescription(`Must provide a command or an event to reload.`).setColor('RED') && message.reply(em); 19 | 20 | const commands = client.commands.get(args[0]) || client.commands.get(client.aliases.get(args[0])); 21 | const events = client.events.get(args[0]); 22 | if(commands) { 23 | let response = await client.unloadCommand(commands.conf.location, commands.help.name); 24 | if (response) return em.setDescription(`Error unloading command: ${response}`).setColor('RED') && message.channel.send(em); 25 | 26 | response = client.loadCommand(commands.conf.location, commands.help.name); 27 | if (response) return em.setDescription(`Error loading command: ${response}`).setColor('RED') && message.channel.send(em); 28 | 29 | em.setDescription(`The command \`${commands.help.name}\` has been reloaded`).setColor('GREEN') 30 | message.channel.send(em); 31 | }else if(events){ 32 | //let response = await client.unloadEvent(events.conf.location, events.conf.name); 33 | //if (response) return em.setDescription(`Error unloading event: ${response}`).setColor('RED') && message.channel.send(em); 34 | 35 | //let response = await client.reloadEvent(events.conf.location, events.conf.name); 36 | //if (response) return em.setDescription(`Error reloading event: ${response}`).setColor('RED') && message.channel.send(em); 37 | 38 | //em.setDescription(`The event \`${events.conf.name}\` has been reloaded`).setColor('GREEN') 39 | em.setDescription(`The events cannot be reloaded yet.`).setColor('RED') 40 | message.channel.send(em); 41 | }else{ 42 | em.setDescription(`\`${args[0]}\` does not exist, nor is it an alias.`).setColor('RED'); 43 | return message.channel.send(em); 44 | } 45 | } 46 | } 47 | module.exports = Reload; 48 | -------------------------------------------------------------------------------- /bot/commands/System/restart.js: -------------------------------------------------------------------------------- 1 | const Command = require('@bot/base/Command'); 2 | const colors = require('colors'); 3 | 4 | class RestartCMD extends Command { 5 | constructor (client) { 6 | super(client, { 7 | name: "restart", 8 | description: "Restarts the bot", 9 | category: "System", 10 | usage: "", 11 | aliases: ['reboot'], 12 | permLevel: "Site Admin" 13 | }); 14 | } 15 | 16 | async run (client, message, args, MessageEmbed) { 17 | await client.database.reboot.ensure(); 18 | const em = new MessageEmbed().setColor('#ff0000').setTitle("System Rebooting").setFooter("All Void Bots services will go down temporarily!!").setDescription("Cya later! I'll be back after I get milk!"); 19 | await console.log(colors.red(`\n-- System Rebooting -- `) + colors.yellow(message.author.tag) + colors.red(` --\n`)) 20 | await message.channel.send(em).then(async (m) => { 21 | await client.database.reboot.update({ rebooted: true, channelid: m.channel.id, messageid: m.id, ranuser: message.author.tag }); 22 | }); 23 | process.exit(0); 24 | } 25 | } 26 | 27 | module.exports = RestartCMD; 28 | -------------------------------------------------------------------------------- /bot/commands/Utility/bump.js: -------------------------------------------------------------------------------- 1 | const Command = require('@bot/base/Command'); 2 | const Servers = require('@models/servers') 3 | 4 | class BumpCMD extends Command { 5 | constructor (client) { 6 | super(client, { 7 | name: "bump", 8 | description: "Bump the server higher on the list.", 9 | category: "Utility", 10 | usage: "", 11 | aliases: ["bumpserver", "serverbump"], 12 | permLevel: "User" 13 | }); 14 | } 15 | 16 | async run (client, message, args, MessageEmbed) { 17 | const embed = new MessageEmbed() 18 | .setColor('PURPLE') 19 | .setFooter(message.author.username, message.author.avatarURL()) 20 | .setTitle(`Void Servers » Bump`) 21 | 22 | let server = await Servers.findOne({guildid: message.guild.id}, { _id: false }) 23 | if(!server) { 24 | embed.setDescription('An error occured, please contact a site administator.') 25 | return message.channel.send(embed); 26 | } 27 | 28 | const timeremain = getTimeRemaining(server.lastbumped) 29 | if(timeremain.days == 0) 30 | if(timeremain.hours < 2) { 31 | embed.setDescription(`Too early! Please come back in \n${1-timeremain.hours} hours, ${59-timeremain.minutes} minutes, ${60-timeremain.seconds} seconds.`) 32 | return message.channel.send(embed) 33 | } 34 | await Servers.updateOne({ guildid: server.guildid }, {$set: { lastbumped: new Date(Date.parse(new Date())) } }) 35 | 36 | embed.setDescription('Successfully bumped!') 37 | message.channel.send(embed); 38 | } 39 | } 40 | 41 | function getTimeRemaining(endtime) { 42 | const total = Date.parse(new Date()) - Date.parse(endtime); 43 | const seconds = Math.floor((total / 1000) % 60); 44 | const minutes = Math.floor((total / 1000 / 60) % 60); 45 | const hours = Math.floor((total / (1000 * 60 * 60)) % 24); 46 | const days = Math.floor(total / (1000 * 60 * 60 * 24)); 47 | return { total, days, hours, minutes, seconds }; 48 | } 49 | 50 | module.exports = BumpCMD; 51 | -------------------------------------------------------------------------------- /bot/commands/Utility/help.js: -------------------------------------------------------------------------------- 1 | const Command = require('@bot/base/Command'); 2 | 3 | class HelpCMD extends Command { 4 | constructor (client) { 5 | super(client, { 6 | name: "help", 7 | description: "Shows the commands in the bot.", 8 | category: "Utility", 9 | usage: "[command]", 10 | aliases: [], 11 | permLevel: "User" 12 | }); 13 | } 14 | 15 | async run (client, message, args, MessageEmbed) { 16 | const level = client.permLevel(message); 17 | const embed = new MessageEmbed() 18 | .setColor('LUMINOUS_VIVID_PINK') 19 | .setFooter(`${message.author.username} • Use ${process.env.PREFIX}help for command details.`, message.author.avatarURL()); 20 | // If args[0] then show the command's information. 21 | if (!args[0]) { 22 | // Filter all commands by which are available for the user's level, using the .filter() method. 23 | const myCommands = client.commands.filter(cmd => cmd.help.category != "System"); 24 | /* 25 | // Here we have to get the command names only, and we use that array to get the longest name. 26 | // This make the help commands "aligned" in the output. 27 | const commandNames = myCommands.keyArray(); 28 | const commands = {}; 29 | 30 | commandNames.forEach((cmd) => { 31 | const command = myCommands.get(cmd).help; 32 | if(!commands[command.category.toLowerCase()]) commands[command.category.toLowerCase()] = []; 33 | commands[command.category.toLowerCase()].push(command); 34 | }); 35 | 36 | let categories = Object.keys(commands); 37 | categories.forEach((cat) => { 38 | let output = []; 39 | commands[cat].forEach((cmd) => { 40 | output.push(`\`${process.env.PREFIX}${cmd.name} ${cmd.usage}\` - ${cmd.description}`); 41 | }) 42 | embed.addField(`${cat.toProperCase()}`, output) 43 | });*/ 44 | 45 | 46 | let output = []; 47 | myCommands.forEach((cmd) => { 48 | output.push(`\`${process.env.PREFIX}${cmd.help.name}${cmd.help.usage ? ' ' : ''}${cmd.help.usage}\` - ${cmd.help.description}`) 49 | }); 50 | 51 | 52 | 53 | embed 54 | .setTitle(`Void Servers » Help`) 55 | .setDescription(`I am a bot for Void Servers (https://voidlist.xyz) :robot:`) 56 | .addField('Commands', output.join('\n')) 57 | message.channel.send(embed); 58 | } else { 59 | if(args[0] == "dev" || args[0] == "developer" || args[0] == "system") { 60 | const myCommands = client.commands.filter(cmd => cmd.help.category == "System"); 61 | let output = []; 62 | myCommands.forEach((cmd) => { 63 | output.push(`\`${process.env.PREFIX}${cmd.help.name}${cmd.help.usage ? ' ' : ''}${cmd.help.usage}\` - ${cmd.help.description}`) 64 | }); 65 | embed 66 | .setTitle(`Void Servers » Help (Developers)`) 67 | .setDescription(`I am a bot for Void Servers (https://voidlist.xyz) :robot:`) 68 | .addField('Commands', output.join('\n')) 69 | message.channel.send(embed); 70 | } 71 | // Show individual command's help. 72 | let command = args[0]; 73 | if (client.commands.has(command) || client.commands.has(client.aliases.get(command))) { 74 | command = client.commands.get(command); 75 | embed 76 | .setTitle(`Help » ${command.help.name.toProperCase()}`) 77 | .addField(`Description`, command.help.description || "None") 78 | .addField(`Usage`, `${process.env.PREFIX}${command.help.name} ${command.help.usage}` || "None") 79 | .addField(`Aliases`, command.conf.aliases.join(', ') || "None") 80 | .addField(`Permission Level`, command.conf.permLevel || "Error", true) 81 | .addField(`Category`, command.help.category || "Error", true); 82 | message.channel.send(embed); 83 | } 84 | } 85 | } 86 | } 87 | 88 | module.exports = HelpCMD; 89 | -------------------------------------------------------------------------------- /bot/commands/Utility/info.js: -------------------------------------------------------------------------------- 1 | const Command = require("@bot/base/Command.js"); 2 | const Servers = require("@models/servers"); 3 | const moment = require('moment'); 4 | 5 | class InfoCMD extends Command { 6 | constructor (client) { 7 | super(client, { 8 | name: "info", 9 | description: "Get information about a server.", 10 | category: "Utility", 11 | usage: "[server name/server_id]", 12 | aliases: ['si', 'serinfo', 'serverinfo'], 13 | permLevel: "User", 14 | guildOnly: true, 15 | }); 16 | } 17 | 18 | async run (client, message, args, MessageEmbed) { 19 | let infoGuild = message.guild; 20 | if (!args || args.length < 1) { 21 | infoGuild = message.guild; 22 | } else { 23 | infoGuild = client.guilds.cache.find(m => m.id === `${args.join(' ')}`) || client.guilds.cache.find(m => m.name.toUpperCase() === `${args.join(' ').toUpperCase()}`) || client.guilds.cache.find(m => m.name.toLowerCase().includes(`${args.join(' ').toLowerCase()}`));; 24 | } 25 | 26 | if (!infoGuild) { 27 | infoGuild = message.guild; 28 | //const e = new MessageEmbed() 29 | // .setColor('RED') 30 | // .setDescription('There might be duplicates of that server\'s name or I dont have a guild with that name') 31 | //return message.channel.send(e); 32 | } 33 | 34 | let dbInfo = await Servers.findOne({guildid: infoGuild.id}, { _id: false }) 35 | if (!dbInfo) { 36 | const e = new MessageEmbed() 37 | .setColor('RED') 38 | .setDescription('That guild is not in our dB. Contact a site admin.') 39 | return message.channel.send(e); 40 | } 41 | 42 | // return console.log(infoGuild); 43 | 44 | const then = moment(infoGuild.createdAt); 45 | const time = then.from(moment()); 46 | const ca = then.format("MMM Do, YYYY"); 47 | 48 | // const roles = infoGuild.roles.cache.sort((a, b) => b.position - a.position); 49 | // let roles1 = roles.array().join(', '); 50 | // if (roles1 === undefined || roles1.length == 0) roles1 = "No Roles"; 51 | // if (roles1.length > 1020) { 52 | // roles1 = roles1.substring(0, 1020).replace(/,[^,]+$/, ""); 53 | // roles1 = roles1 + " ..."; 54 | // } 55 | 56 | let lvl = "", lvlnum = 0; 57 | switch (infoGuild.verificationLevel.toProperCase()) { 58 | case "None": 59 | lvl = "None" 60 | lvlnum = 0; 61 | break; 62 | 63 | case "Low": 64 | lvl = "Low" 65 | lvlnum = 1; 66 | break; 67 | 68 | case "Medium": 69 | lvl = "Medium" 70 | lvlnum = 2; 71 | break; 72 | 73 | case "High": 74 | lvl = "(╯°□°)╯︵ ┻━┻" 75 | lvlnum = 3; 76 | break; 77 | 78 | case "Very_high": 79 | lvl = "┻━┻彡 ヽ(ಠ益ಠ)ノ彡┻━┻'" 80 | lvlnum = 4; 81 | break; 82 | 83 | default: 84 | break; 85 | } 86 | 87 | let flag = ":map:"; 88 | if (infoGuild.region.toProperCase() == "Brazil") flag = ":flag_br:" 89 | if (infoGuild.region.toProperCase() == "Europe") flag = ":flag_eu:" 90 | if (infoGuild.region.toProperCase() == "Hongkong") flag = ":flag_hk:" 91 | if (infoGuild.region.toProperCase() == "India") flag = ":flag_in:" 92 | if (infoGuild.region.toProperCase() == "Japan") flag = ":flag_jp:" 93 | if (infoGuild.region.toProperCase() == "Russia") flag = ":flag_ru:" 94 | if (infoGuild.region.toProperCase() == "Singapore") flag = ":flag_sg:" 95 | if (infoGuild.region.toProperCase() == "Southafrica") flag = ":flag_ss:" 96 | if (infoGuild.region.toProperCase() == "Sydney") flag = ":flag_sh:" 97 | if (["Us-Central", "Us-West", "Us-East", "Us-South"].includes(infoGuild.region.toProperCase())) flag = ":flag_us:" 98 | 99 | let color = "LUMINOUS_VIVID_PINK"; 100 | if(dbInfo && dbInfo.styles && dbInfo.styles.background) { 101 | if(dbInfo.styles.background == "rbg") color = "#FF0000"; 102 | if(dbInfo.styles.background == "bgg") color = "#0009FF"; 103 | if(dbInfo.styles.background == "pyb") color = "#AB00FF"; 104 | if(dbInfo.styles.background == "pcg") color = "#FF00F1"; 105 | if(dbInfo.styles.background == "oyg") color = "#FF5E00"; 106 | if(dbInfo.styles.background == "lcg") color = "#30FF00"; 107 | if(dbInfo.styles.background == "plg") color = "#E700FF"; 108 | if(dbInfo.styles.background == "pog") color = "#FF8000"; 109 | if(dbInfo.styles.background == "bcg") color = "#1D00FF"; 110 | if(dbInfo.styles.background == "rdg") color = "#B91515"; 111 | if(dbInfo.styles.background == "pdg") color = "#5D03DB"; 112 | if(dbInfo.styles.background == "blk") color = "#010101"; 113 | if(dbInfo.styles.background == "db") color = "#7289DA"; 114 | if(dbInfo.styles.background == "dnqb") color = "#23272A"; 115 | if(dbInfo.styles.background == "dg") color = "#9F9F9F"; 116 | //if(dbInfo.styles.background == "invitebg") color = "#202225"; 117 | //if(dbInfo.styles.background == "banner") color = "#202225"; 118 | }; 119 | 120 | const embed = new MessageEmbed() 121 | .setAuthor(`${infoGuild.name} | ID: ${infoGuild.id}`, infoGuild.iconURL()) 122 | .setColor(color) 123 | .setThumbnail(infoGuild.iconURL({ format: 'png', dynamic: true})) 124 | .setFooter(message.author.username, message.author.avatarURL()) 125 | .addField('Owner', infoGuild.owner.user.tag, true) 126 | .addField(`Created At [${time}]`, `${ca}`, true) 127 | .addField('\u200b', '\u200b', true) 128 | .addField(`Last Bumped [${moment(dbInfo.lastbumped).fromNow()}]`, moment(dbInfo.lastbumped).format('LLL'), true) 129 | .addField('Emojis', infoGuild.emojis.cache.size, true) 130 | .addField('\u200b', '\u200b', true) 131 | .addField(`Verification Level [${lvlnum}]`, lvl, true) 132 | .addField(`Region [${infoGuild.region.toProperCase()}]`, flag, true) 133 | .addField('\u200b', '\u200b', true) 134 | .addField(`Members [${infoGuild.memberCount}/${infoGuild.maximumMembers}]`, `🧍 ${infoGuild.members.cache.filter(m => !m.user.bot).size} | 🤖 ${infoGuild.members.cache.filter(m => m.user.bot).size} | ${infoGuild.premiumSubscriptionCount}`, true) 135 | .addField(`Channels [${infoGuild.channels.cache.size}]`, `⌨️ ${infoGuild.channels.cache.filter(c => c.type == "text").size} | 🔈 ${infoGuild.channels.cache.filter(c => c.type == "voice").size} | 📁 ${infoGuild.channels.cache.filter(c => c.type == "category").size} | 📢 ${infoGuild.channels.cache.filter(c => c.type == "news").size}`, true) 136 | .addField('\u200b', '\u200b', true) 137 | .addField(`Vanity`, dbInfo.vanity.code ? `https://di.scord.xyz/${dbInfo.vanity.code}` : "Not set", true) 138 | .addField(`Boost Level`, `${infoGuild.premiumTier}`, true) 139 | // .addField('AFK Channel', `${(infoGuild.afkChannel && infoGuild.afkChannel.name) || "Not Set"}`, true) 140 | // .addField(`Roles (${infoGuild.roles.cache.size.toLocaleString()})`, roles1 141 | 142 | message.channel.send(embed); 143 | } 144 | } 145 | 146 | module.exports = InfoCMD; 147 | -------------------------------------------------------------------------------- /bot/commands/Utility/invite.js: -------------------------------------------------------------------------------- 1 | const Command = require('@bot/base/Command'); 2 | const Servers = require("@models/servers"); 3 | 4 | class InviteCMD extends Command { 5 | constructor (client) { 6 | super(client, { 7 | name: "invite", 8 | description: "Change Instant Invite to this channel. If [channel] is specified, create Instant Invite for that channel (Admin only)", 9 | category: "Utility", 10 | usage: "[channel]", 11 | aliases: ["invitechannel", "invitechan", "setinvite"], 12 | permLevel: "User" 13 | }); 14 | } 15 | 16 | async run (client, message, args, MessageEmbed) { 17 | if(!message.guild.me.permissions.has(1)) return message.channel.send('I need the permission `CREATE_INVITE` for this command.'); 18 | let selectedchannel = message.mentions.channels.first() || message.channel; 19 | 20 | let invite = await selectedchannel.createInvite({ maxAge: 0, maxUses: 0 }).catch(() => {}); 21 | if(!invite) return message.channel.send(`I could not create an invite to ${selectedchannel}`); 22 | 23 | await Servers.updateOne({ guildid: message.guild.id }, {$set: { invite } }) 24 | 25 | const embed = new MessageEmbed() 26 | .setColor('PURPLE') 27 | .setFooter(message.author.username, message.author.avatarURL()) 28 | .setTitle(`Void Servers » Invite Link`) 29 | .setDescription(`The Instant Invite has been set!`) 30 | .addField('Channel', `${selectedchannel}`) 31 | .addField('Instant Invite', `${invite}`) 32 | message.channel.send(embed); 33 | } 34 | } 35 | 36 | module.exports = InviteCMD; 37 | -------------------------------------------------------------------------------- /bot/commands/Utility/page.js: -------------------------------------------------------------------------------- 1 | const Command = require('@bot/base/Command'); 2 | 3 | class PageCMD extends Command { 4 | constructor (client) { 5 | super(client, { 6 | name: "page", 7 | description: "Get server page link", 8 | category: "Utility", 9 | usage: "[command]", 10 | aliases: ["guild", "link", "guildlink"], 11 | permLevel: "User" 12 | }); 13 | } 14 | 15 | async run (client, message, args, MessageEmbed) { 16 | const embed = new MessageEmbed() 17 | .setColor('PURPLE') 18 | .setFooter(message.author.username, message.author.avatarURL()) 19 | .setTitle(`Void Servers » Guild Link`) 20 | .setDescription(`${process.env.DOMAIN}/server/${message.guild.id}`) 21 | message.channel.send(embed); 22 | } 23 | } 24 | 25 | module.exports = PageCMD; 26 | -------------------------------------------------------------------------------- /bot/commands/Utility/ping.js: -------------------------------------------------------------------------------- 1 | const Command = require("../../base/Command.js"); 2 | 3 | class PingCMD extends Command { 4 | constructor (client) { 5 | super(client, { 6 | name: "ping", 7 | description: "Latency and API response times.", 8 | category: "Utility", 9 | usage: "", 10 | aliases: ["pong"], 11 | guildOnly: false 12 | }); 13 | } 14 | 15 | async run (client, message, args, MessageEmbed) { // eslint-disable-line no-unused-vars 16 | 17 | const e1 = new MessageEmbed() 18 | .setTitle('Pinging...') 19 | .setImage(`https://discordemoji.com/assets/emoji/loading.gif`) 20 | .setColor('GREEN') 21 | let msg = await message.channel.send(e1); 22 | 23 | const e2 = new MessageEmbed() 24 | .setTitle(':ping_pong: Pong!') 25 | .setColor('GREEN') 26 | .setDescription(`Latency is ${(msg.createdTimestamp - message.createdTimestamp)}ms.\nAPI Latency is ${Math.round(client.ws.ping)}ms`) 27 | .setFooter(message.author.username, message.author.avatarURL()) 28 | setTimeout(() => { 29 | msg.edit(e2); 30 | }, 10); 31 | } 32 | } 33 | 34 | module.exports = PingCMD; 35 | -------------------------------------------------------------------------------- /bot/commands/Utility/vanityurl.js: -------------------------------------------------------------------------------- 1 | const Command = require('@bot/base/Command'); 2 | 3 | class PageCMD extends Command { 4 | constructor (client) { 5 | super(client, { 6 | name: "page", 7 | description: "Get server page link", 8 | category: "Utility", 9 | usage: "[command]", 10 | aliases: ["guild", "link", "guildlink"], 11 | permLevel: "User" 12 | }); 13 | } 14 | 15 | async run (client, message, args, MessageEmbed) { 16 | const embed = new MessageEmbed() 17 | .setColor('PURPLE') 18 | .setFooter(message.author.username, message.author.avatarURL()) 19 | .setTitle(`Void Servers » Guild Link`) 20 | .setDescription(`${process.env.DOMAIN}/server/${message.guild.id}`) 21 | message.channel.send(embed); 22 | } 23 | } 24 | 25 | module.exports = PageCMD; 26 | -------------------------------------------------------------------------------- /bot/database/Database.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const classes = require('./classes'); 3 | 4 | /** 5 | * The Database used by the client 6 | */ 7 | class Database { 8 | /** 9 | * This creates the database functions 10 | * @param {*} client 11 | * @property fn 12 | */ 13 | constructor(client) { 14 | this.client = client; 15 | //this.modals = {}; 16 | 17 | // get the files from classes and assign them. 18 | for (const i in classes) { 19 | this[i.toLowerCase()] = new classes[i](this.client, this, require(`@models/${i.toLowerCase()}.js`)); 20 | //Object.assign(this[i.toLowerCase()], { fn: new classes[i](this.client, this), modal: require(`./models/${i.toLowerCase()}.js`) }) 21 | //Object.assign(this.models, { [i.toLowerCase()]: require(`./models/${i.toLowerCase()}.js`) }); 22 | } 23 | } 24 | } 25 | 26 | module.exports = Database; 27 | -------------------------------------------------------------------------------- /bot/database/classes/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // classes 3 | Reboot: require('./reboot.js'), 4 | 5 | }; 6 | -------------------------------------------------------------------------------- /bot/database/classes/reboot.js: -------------------------------------------------------------------------------- 1 | const { isRegExp } = require("util"); 2 | 3 | class Settings { 4 | constructor(client, database, modal) { 5 | this.client = client; 6 | this.database = database; 7 | this.modal = modal; 8 | } 9 | 10 | /** 11 | * Gets the stored data of a guild 12 | * @param {String} guildID 13 | */ 14 | async get() { 15 | const guilddata = await this.modal.findOne({}, { _id: false }) 16 | if(guilddata) { 17 | return guilddata; 18 | } else { 19 | return new Error('No data could be found.'); 20 | } 21 | } 22 | 23 | /** 24 | * Sets the stored data of a guild 25 | * @param {String} guildID 26 | * @param {*} data 27 | */ 28 | async set(guildID, data) { 29 | const guilddb = await this.modal.findOne({}, { _id: false }); 30 | if(!guilddb){ 31 | return await new this.modal(data).save(); 32 | }else{ 33 | return new Error('Data already exists.'); 34 | } 35 | } 36 | 37 | /** 38 | * Deletes the data of a guild 39 | * @param {String} guildID 40 | */ 41 | async delete() { 42 | return await this.modal.findOneAndDelete({}) 43 | } 44 | 45 | async update(data) { 46 | return await this.modal.updateOne({}, {$set: data }) 47 | } 48 | 49 | async ensure() { 50 | const guilddb = await this.modal.findOne({}, { _id: false }); 51 | if(!guilddb){ 52 | let data = { 53 | rebooted: false 54 | }; 55 | await new this.modal(data).save() 56 | return true; 57 | }else{ 58 | return false; 59 | } 60 | } 61 | } 62 | 63 | module.exports = Settings; 64 | -------------------------------------------------------------------------------- /bot/events/guildCreate.js: -------------------------------------------------------------------------------- 1 | const Event = require('@bot/base/Event.js'); 2 | const Servers = require('@models/servers'); 3 | const { MessageEmbed } = require('discord.js'); 4 | const moment = require('moment'); 5 | 6 | module.exports = class extends Event { 7 | constructor (client) { 8 | super(client, { 9 | name: 'guildCreate', 10 | enabled: true, 11 | }); 12 | } 13 | 14 | async run (client, guild) { 15 | await Servers({ guildid: guild.id, description: `${guild.name}'s Description'`, long: `# ${guild.name}` }).save(); 16 | 17 | // Log guild join 18 | const e = new MessageEmbed() 19 | .setTitle(guild.name) 20 | .setThumbnail(guild.iconURL()) 21 | .setColor('GREEN') 22 | .addField('Owner', `${guild.owner.user.tag} \`(${guild.owner.user.id})\``, true) 23 | .addField('Member Count', guild.members.cache.size, true) 24 | .addField('\u200b', '\u200b', true) 25 | .addField('Guild ID', guild.id, true) 26 | .addField('Created At', moment(guild.createdAt).format("LLL"), true) 27 | client.channels.cache.get(process.env.GUILD_LOG).send(e); 28 | client.logger.log(`[GUILD JOIN] ${guild.name} (${guild.id}) added the bot. Owner: ${guild.owner.user.tag} (${guild.owner.user.id})`); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /bot/events/guildDelete.js: -------------------------------------------------------------------------------- 1 | const Event = require('@bot/base/Event.js'); 2 | const Servers = require('@models/servers'); 3 | const { MessageEmbed } = require('discord.js'); 4 | const moment = require('moment'); 5 | 6 | module.exports = class extends Event { 7 | constructor (client) { 8 | super(client, { 9 | name: 'guildDelete', 10 | enabled: true, 11 | }); 12 | } 13 | 14 | async run (client, guild) { 15 | await Servers.findOneAndDelete({guildid: guild.id}); 16 | 17 | // Log it. 18 | const e = new MessageEmbed() 19 | .setTitle(guild.name) 20 | .setThumbnail(guild.iconURL()) 21 | .setColor('RED') 22 | .addField('Owner', `${guild.owner.user.tag} \`(${guild.owner.user.id})\``, true) 23 | .addField('Member Count', guild.members.cache.size, true) 24 | .addField('\u200b', '\u200b', true) 25 | .addField('Guild ID', guild.id, true) 26 | .addField('Created At', moment(guild.createdAt).format("LLL"), true) 27 | client.channels.cache.get(process.env.GUILD_LOG).send(e); 28 | client.logger.log(`[GUILD LEAVE] ${guild.name} (${guild.id}) removed the bot.`); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /bot/events/message.js: -------------------------------------------------------------------------------- 1 | const Event = require('@bot/base/Event.js'); 2 | const colors = require('colors'); 3 | const { MessageEmbed } = require('discord.js'); 4 | 5 | module.exports = class extends Event { 6 | constructor (client) { 7 | super(client, { 8 | name: 'message', 9 | enabled: true, 10 | }); 11 | } 12 | 13 | async run (client, message) { 14 | const { author, channel, content, guild } = message; 15 | if (author.bot) return; 16 | if (guild && !channel.permissionsFor(message.guild.me).missing("SEND_MESSAGES")) return; 17 | //if (message.channel.id == "749432519681900576") message.react(message.guild.emojis.cache.find(e => e.name == "serverbooster")); 18 | 19 | const prefix = process.env.PREFIX; 20 | const fixedPrefix = escapeRegExp(prefix); 21 | const fixedUsername = escapeRegExp(client.user.username); 22 | 23 | const PrefixRegex = new RegExp(`^(<@!?${client.user.id}>|${fixedPrefix}|${fixedUsername})`, 'i', '(\s+)?'); 24 | 25 | let usedPrefix = content.match(PrefixRegex); 26 | usedPrefix = usedPrefix && usedPrefix.length && usedPrefix[0]; 27 | 28 | // Mention related tasks 29 | const MentionRegex = new RegExp(`^(<@!?${client.user.id}>)`); 30 | const mentioned = MentionRegex.test(content); 31 | const helpPrefix = `Sup, you can type \`${process.env.PREFIX}help\` for a list of comamnds!`; 32 | 33 | if(!usedPrefix) return; // Exit if its not using a prefix 34 | const args = message.content.slice(usedPrefix.length).trim().split(/ +/g); 35 | const command = args.shift().toLowerCase(); 36 | 37 | // If the member on a guild is invisible or not cached, fetch them. 38 | if (message.guild && !message.member) await message.guild.members.fetch(message.author); 39 | 40 | // Check whether the command, or alias, exist in the collections defined 41 | const cmd = client.commands.get(command) || client.commands.get(client.aliases.get(command)); 42 | if (!cmd && mentioned) return message.channel.send(helpPrefix); 43 | if (!cmd) return; 44 | 45 | if (cmd && !message.guild && cmd.conf.guildOnly) return message.channel.send("This command is unavailable via private message. Please run this command in a guild."); 46 | 47 | const level = client.permLevel(message); 48 | if (level < client.levelCache[cmd.conf.permLevel]) { 49 | const e = new MessageEmbed() 50 | .setTitle('Umm No..') 51 | .setColor('#2F3136') 52 | .setDescription(cmd.conf.permLevel == 'Lock' ? `The command you entered is disabled!` : `Last time I check, you are not a **${cmd.conf.permLevel}**...`) 53 | .setImage('https://discord.mx/TENvu8AirM.gif') 54 | .setFooter(cmd.conf.permLevel == 'Lock' ? `Error: COMMAND_DISABLED\nErType: Access Denied\nMade by Void Development (https://voiddevs.com/)` : `Error: INVALID_PERMISSIONS\nErType: Access Denied\nMade by Void Development (https://voiddevs.com/)`); 55 | message.channel.send(e); 56 | console.log(colors.yellow(`[${client.perms.find(l => l.level === level).name}] `) + colors.red(`${message.author.username} (${message.author.id}) `) + colors.white(`ran unauthorized command "`) + colors.red(`${cmd.help.name} ${args.join(' ')}`) + colors.white(`"`)); 57 | return; 58 | } 59 | message.author.permLevel = level; 60 | 61 | message.flags = []; 62 | while (args[0] &&args[0][0] === "-") { 63 | message.flags.push(args.shift().slice(1)); 64 | } 65 | 66 | // If the command exists, **AND** the user has permission, run it. 67 | //this.client.logger.log(`${this.client.config.permLevels.find(l => l.level === level).name} ${message.author.username} (${message.author.id}) ran command ${cmd.help.name} ${args.join(' ')}`, "cmd"); 68 | 69 | cmd.run(client, message, args, MessageEmbed); 70 | } 71 | }; 72 | 73 | function escapeRegExp(str) { 74 | return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 75 | } 76 | -------------------------------------------------------------------------------- /bot/events/messageUpdate.js: -------------------------------------------------------------------------------- 1 | const Event = require('@bot/base/Event.js'); 2 | 3 | module.exports = class extends Event { 4 | constructor (client) { 5 | super(client, { 6 | name: 'messageUpdate', 7 | enabled: true, 8 | }) 9 | } 10 | 11 | async run (client, oldMessage, newMessage) { 12 | // Cancel if nothing changed. (Text not changing? Accidential fire?) 13 | if(oldMessage == newMessage || oldMessage.content == newMessage.content) return; 14 | client.emit('message', newMessage); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /bot/events/ready.js: -------------------------------------------------------------------------------- 1 | const Event = require('@bot/base/Event.js'); 2 | const mongoose = require("mongoose"); 3 | const colors = require('colors'); 4 | const App = require('@structures/app.js'); 5 | 6 | module.exports = class extends Event { 7 | constructor (client) { 8 | super(client, { 9 | name: 'ready', 10 | enabled: true, 11 | }); 12 | } 13 | 14 | async run (client) { 15 | await setTimeout(() => {}, 1000) 16 | 17 | 18 | client.appInfo = await client.fetchApplication(); 19 | setInterval(async () => { 20 | client.appInfo = await client.fetchApplication(); 21 | }, 60000); 22 | 23 | await mongoose.connect(process.env.MONGO_DB_URL, { 24 | useCreateIndex: true, 25 | useNewUrlParser: true, 26 | useUnifiedTopology: true 27 | }); 28 | 29 | console.log(` `); 30 | console.log(` `); 31 | console.log(colors.grey(`---------------------------------------------------`)); 32 | console.log(colors.yellow(`VoidServers was Created by `) + colors.underline.green(`DanPlayz`) + colors.yellow(` and `) + colors.underline.green(`AshMW`)); 33 | console.log(colors.yellow(`Connected to the `) + colors.underline.green(`VoidServers`) +colors.yellow(` database`)); // "on colors.underline.green(MONGO_DB_URL)" 34 | console.log(colors.yellow(`Successfully logged into `) + colors.underline.green(client.user.tag)); 35 | 36 | 37 | await new App(client).listen(process.env.PORT || 8080); 38 | console.log(colors.yellow(`Running on port `) + colors.underline.green(process.env.PORT || 8080)); 39 | 40 | console.log(colors.grey(`---------------------------------------------------`)); 41 | console.log(` `); 42 | console.log(` `); 43 | 44 | function setActivity() { 45 | //client.user.setActivity(, {type: "WATCHING", status: "dnd"}); 46 | client.user.setPresence({ status: 'dnd', activity: { name: `over ${client.guilds.cache.size} servers | vs.help | www.VoidList.xyz`, type: 'WATCHING'}}) 47 | // client.user.setPresence({ status: 'dnd', activity: { name: `my developers build me! (Coming soon)`, type: 'WATCHING'}}) 48 | }; 49 | 50 | setActivity(); 51 | setInterval(setActivity, 120000); 52 | 53 | try { 54 | 55 | let aaa = await client.database.reboot.get(); 56 | if(client.channels.cache.get(process.env.BOT_LOGS)){ 57 | if (aaa.rebooted == "true") { 58 | client.channels.cache.get(process.env.BOT_LOGS).send(`**The bot has been restarted by** \`User: ${aaa.ranuser}\`**!**`); 59 | } else { 60 | client.channels.cache.get(process.env.BOT_LOGS).send(`**The bot has been restarted by** \`Unknown\`**!**`); 61 | } 62 | } 63 | 64 | if(aaa.rebooted === "true") { 65 | await client.channels.cache.get(aaa.channelid).messages.fetch(aaa.messageid).then(message => { 66 | const { MessageEmbed } = require('discord.js'); 67 | const em = new MessageEmbed() 68 | .setColor('GREEN') 69 | .setTitle("System Rebooted") 70 | .setFooter("Successfully rebooted all Void Bots systems!!") 71 | .setDescription("Honey, I'm home!"); 72 | message.edit(em); 73 | }); 74 | 75 | await client.database.reboot.update({ rebooted: false, ranuser: null }); 76 | } 77 | }catch(err){} 78 | } 79 | }; 80 | -------------------------------------------------------------------------------- /dynamic/blocks/footer.ejs: -------------------------------------------------------------------------------- 1 |
2 |

DMCA.com Protection Status

3 | 4 |

Designed by AshMW Developed by DanPlayz

5 | 10 |
11 | -------------------------------------------------------------------------------- /dynamic/blocks/guildtop.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

5 | <% if (guild.icon) { %> 6 | 7 | <% } else { %> 8 | 9 | 19 | <% } %> 20 |

21 |
22 |
23 |

<%- guild.id == "733135938347073576" ? ` ` : '' %><%= guild.name %>
<%= server.description %>

24 |
25 |
26 |
27 |
28 | 166 | -------------------------------------------------------------------------------- /dynamic/blocks/header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 40 | 89 | -------------------------------------------------------------------------------- /dynamic/blocks/navbar.ejs: -------------------------------------------------------------------------------- 1 | 67 | 82 | 91 | 122 | -------------------------------------------------------------------------------- /dynamic/errors/403.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - Error 403 4 | <%- include('../blocks/header') %> 5 | 6 | 7 | <%- include('../blocks/navbar', { bot, user }) %> 8 |
9 |
10 |
11 |

12 |
13 |
14 |

Error 403
Access denied!

15 |
16 |
17 |
18 |
19 | <%- include('../blocks/footer') %> 20 | 21 | 22 | -------------------------------------------------------------------------------- /dynamic/errors/404.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - Error 404 4 | <%- include('../blocks/header') %> 5 | 6 | 7 | <%- include('../blocks/navbar', { bot, user }) %> 8 |
9 |
10 |
11 |

12 |
13 |
14 |

Error 404
Page not found!

15 |
16 |
17 |
18 |
19 | <%- include('../blocks/footer') %> 20 | 21 | 22 | -------------------------------------------------------------------------------- /dynamic/errors/express.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - Internal Error 4 | <%- include('../blocks/header') %> 5 | 6 | 7 | 8 | 9 | <%- include('../blocks/navbar', { bot, user }) %> 10 |
11 |
12 |
13 |

14 |
15 |
16 |

Internal Error (<%= status %>)
Please tell a administrator to check the system console!

17 |
18 |
19 |
20 |
21 | 22 | <% if (user && user.isAdmin == true) { %> 23 |
24 |
25 |
26 |
27 |
Express Error Message
28 |
29 |
<%= error.message %>
30 |
31 |
32 |
33 |
34 |
35 | <% } %> 36 | <%- include('../blocks/footer') %> 37 | 38 | 39 | -------------------------------------------------------------------------------- /dynamic/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Void Servers 10 | 11 | 12 | 13 | 14 | <%- include('./blocks/header') %> 15 | 16 | 17 |
18 |
19 |
20 |

21 |
22 |
23 |

Void Server ListBETA

24 |
25 |
26 |
27 |
28 | <%- include('./blocks/navbar', { bot, user }) %> 29 | 30 |
31 |
32 |
33 |

Recently Bumped

34 |

Below are the most recently bumped servers!

35 |
36 | 37 |
38 |
39 | <% let cards = servers.sort((a, b) => b.lastbumped - a.lastbumped).slice(0, 8) 40 | if (cards.length === 0) { %> 41 |
No bots found. 42 | <% } else { %> 43 | <% for(let i of cards) { %> 44 |
45 |
46 |
47 | <% if (bot.guilds.cache.get(i.guildid).icon) { %> 48 | 49 | 50 | <% } else { %> 51 | 52 | 62 | <% } %> 63 | 64 |

<%= bot.guilds.cache.get(i.guildid).name %>

65 |

<%= (i.description).slice(0, 55) %><%= (i.description).length > 55 ? "..." : "" %>

66 |
67 | 72 |
73 |
74 | <% } %> 75 | <% } %> 76 |
77 |

78 |
79 |
80 |

Recently Added

81 |

Below are the most recently added servers!

82 |
83 | 84 |
85 |
86 | <% cards = servers.sort((a, b) => b.addedAt - a.addedAt).slice(0, 8) 87 | if (cards.length === 0) { %> 88 |
No bots found. 89 | <% } else { %> 90 | <% for(let i of cards) { %> 91 |
92 |
93 |
94 | <% if (bot.guilds.cache.get(i.guildid).icon) { %> 95 | 96 | <% } else { %> 97 | 98 | 108 | <% } %> 109 | 110 |

<%= bot.guilds.cache.get(i.guildid).name %>

111 |

<%= (i.description).slice(0, 55) %><%= (i.description).length > 55 ? "..." : "" %>

112 |
113 | 118 |
119 |
120 | <% } %> 121 | <% } %> 122 |
123 |

124 |
125 |
126 |

Most Members

127 |

Below are the servers with the highest member count!

128 |
129 | 130 |
131 |
132 | <% cards = servers.sort((a, b) => bot.guilds.cache.get(b.guildid).members.cache.size - bot.guilds.cache.get(a.guildid).members.cache.size).slice(0, 8) 133 | if (cards.length === 0) { %> 134 |
No bots found. 135 | <% } else { %> 136 | <% for(let i of cards) { %> 137 |
138 |
139 |
140 | <% if (bot.guilds.cache.get(i.guildid).icon) { %> 141 | 142 | <% } else { %> 143 | 144 | 154 | <% } %> 155 | 156 |

<%= bot.guilds.cache.get(i.guildid).name %>

157 |

<%= (i.description).slice(0, 55) %><%= (i.description).length > 55 ? "..." : "" %>

158 |
159 | 164 |
165 |
166 | <% } %> 167 | <% } %> 168 |
169 |
170 |

171 | <%- include('./blocks/footer') %> 172 | 173 | 221 | 235 | 236 | -------------------------------------------------------------------------------- /dynamic/me/add.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /dynamic/me/admin.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - All Servers 4 | <%- include('../blocks/header') %> 5 | 6 | 7 | <%- include('../blocks/navbar', { bot, user }) %> 8 |
9 |
10 |
11 |

12 |
13 |
14 |

All Servers
Below is a list of servers that the bot has access to.

15 |
16 |
17 |
18 |


19 |
20 |
21 | <% if (cards.length === 0) { %> 22 |
23 |
24 |
25 | 26 |

No Servers

27 |

Bot has no servers.

28 |
29 |
30 |
31 | <% } else { %> 32 | <% for(let i of cards) { %> 33 |
34 |
35 |
36 | <% if (bot.guilds.cache.get(i.guildid).icon) { %> 37 | 38 | <% } else { %> 39 | 40 | 50 | <% } %> 51 |

<%= bot.guilds.cache.get(i.guildid).name %>

52 |

<%= i.description.length > 55 ? `${i.description.slice(0,55)}...` : i.description %>

53 |
54 | 61 |
62 |
63 | <% } %> 64 | <% } %> 65 |
66 |


67 | 86 | <%- include('../blocks/footer') %> 87 | 94 | 95 | 137 | 138 | -------------------------------------------------------------------------------- /dynamic/me/servers.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - My Servers 4 | <%- include('../blocks/header') %> 5 | 6 | 7 | <%- include('../blocks/navbar', { bot, user }) %> 8 |
9 |
10 |
11 |

12 |
13 |
14 |

Your Servers
Below is a list of servers that you have access to.

15 |
16 |
17 |
18 |


19 |
20 |
21 | <% let cards = servers.filter(a => bot.guilds.cache.get(a.guildid).members.cache.has(user.id)).filter(a => bot.guilds.cache.get(a.guildid).members.cache.get(user.id).permissions.has('MANAGE_GUILD')) 22 | if (cards.length === 0) { %> 23 |
24 |
25 |
26 | 27 |

No Servers

28 |

You have no servers.

29 |
30 | 33 |
34 |
35 | <% } else { %> 36 | <% for(let i of cards) { %> 37 |
38 |
39 |
40 | <% if (bot.guilds.cache.get(i.guildid).icon) { %> 41 | 42 | <% } else { %> 43 | 44 | 54 | <% } %> 55 |

<%= bot.guilds.cache.get(i.guildid).name %>

56 |

<%= i.description.length > 55 ? `${i.description.slice(0,55)}...` : i.description %>

57 |
58 | 62 |
63 |
64 | <% } %> 65 | <% } %> 66 |
67 |


68 | <%- include('../blocks/footer') %> 69 | 70 | 112 | 113 | -------------------------------------------------------------------------------- /dynamic/me/settings.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%- include('../blocks/header') %> 4 | 5 | 6 | <%- include('../blocks/navbar', { bot, user }) %> 7 |
8 |
9 |
10 |

11 |
12 |
13 |

Your Settings
Below is all the settings you can use to customize your experience.

14 |
15 |
16 |
17 |


18 |
19 |
20 |
21 |
22 |
Coming soon!
23 |
24 |
25 |
26 |
27 | 28 |

29 | <%- include('../blocks/footer') %> 30 | 31 | 32 | -------------------------------------------------------------------------------- /dynamic/partners.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%- include('./blocks/header') %> 4 | Void Servers - Partners 5 | 6 | 7 | 8 | 9 | 10 | 11 | <%- include('./blocks/navbar', { bot, user }) %> 12 |
13 |
14 |
15 |

16 |
17 |
18 |

Partners
They are just amazing!

19 |
20 |
21 |
22 |


23 |
24 |
25 |
26 |
27 |
28 |

29 | The following privacy policy outlines how your data is used on our website. The site administration has the right to change this privacy policy at any point without warning.

30 | Data
31 | Basic non-identifiable information about your user on the website is collected; the majority of which is provided during first-time login, such as email addresses and usernames.
32 | In addition to this, IP addresses for registered users are stored within the system to aid with moderation duties. This includes spam prevention, and detecting alternative accounts.

33 | Account data can be deleted by a site administrator upon request, which will remove all data relating to your user from our system.

34 | Cookies
35 | Cookies are used to store small pieces of non-identifiable information with your consent. In order to consent to the use of cookies, by using our website you consent to the use of cookies.
36 | Data stored by cookies include Discord IDs, Discord discriminator, Discord avatar, along with a unique token, and a unidentifiable hash.

37 | Arc
38 | VoidList.xyz is faster with Arc. Arc loads content from people's devices near you instead of from slower servers. In return, it helps your device provide content to others.
39 | Arc lets VoidList.xyz earn money with less ads. Just by being here, you share a little bandwidth for VoidList.xyz and help create a faster Internet with fewer ads.
40 | You're safe and in control. Arc doesn't impact your data or performance, and you can opt out any time.
41 | Learn more about Arc here!

44 |
45 |
46 |
47 |
48 |
49 | 50 |

51 | <%- include('./blocks/footer') %> 52 | 53 | 54 | -------------------------------------------------------------------------------- /dynamic/privacy.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%- include('./blocks/header') %> 4 | Void Servers - Privacy Policy 5 | 6 | 7 | 8 | 9 | 10 | 11 | <%- include('./blocks/navbar', { bot, user }) %> 12 |
13 |
14 |
15 |

16 |
17 |
18 |

Privacy Policy
Legal stuff ¯\_(ツ)_/¯

19 |
20 |
21 |
22 |


23 |
24 |
25 |
26 |
27 |
28 |

29 | The following privacy policy outlines how your data is used on our website. The site administration has the right to change this privacy policy at any point without warning.

30 | Data
31 | Basic non-identifiable information about your user on the website is collected; the majority of which is provided during first-time login, such as email addresses and usernames.
32 | In addition to this, IP addresses for registered users are stored within the system to aid with moderation duties. This includes spam prevention, and detecting alternative accounts.

33 | Account data can be deleted by a site administrator upon request, which will remove all data relating to your user from our system.

34 | Cookies
35 | Cookies are used to store small pieces of non-identifiable information with your consent. In order to consent to the use of cookies, by using our website you consent to the use of cookies.
36 | Data stored by cookies include Discord IDs, Discord discriminator, Discord avatar, along with a unique token, and a unidentifiable hash.

37 | Arc
38 | VoidList.xyz is faster with Arc. Arc loads content from people's devices near you instead of from slower servers. In return, it helps your device provide content to others.
39 | Arc lets VoidList.xyz earn money with less ads. Just by being here, you share a little bandwidth for VoidList.xyz and help create a faster Internet with fewer ads.
40 | You're safe and in control. Arc doesn't impact your data or performance, and you can opt out any time.
41 | Learn more about Arc here!

44 |
45 |
46 |
47 |
48 |
49 | 50 |

51 | <%- include('./blocks/footer') %> 52 | 53 | 54 | -------------------------------------------------------------------------------- /dynamic/search/alltags.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%- include('../blocks/header') %> 4 | 5 | 6 | <%- include('../blocks/navbar', { bot, user }) %> 7 |
8 |
9 |
10 |

11 |
12 |
13 |

All Categories
Below is all the categories you can view.

14 |
15 |
16 |
17 |


18 |
19 |
20 | <% if (allcategories.length === 0) { %> 21 |
22 |
23 |
24 | 25 |

No Categories

26 |

This shouldn't have happened.

27 |
28 | 31 |
32 |
33 | <% } else { %> 34 | <% for(let i of allcategories) { %> 35 | 38 | 39 | <% } %> 40 | <% } %> 41 |
42 |


43 | <%- include('../blocks/footer') %> 44 | 45 | 87 | 88 | -------------------------------------------------------------------------------- /dynamic/search/category.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Void Servers - <%= category.toProperCase() %> 9 | <%- include('../blocks/header') %> 10 | 11 | 12 | <%- include('../blocks/navbar', { bot, user }) %> 13 |
14 |
15 |
16 | <% if (category == "music") { %> 17 |

18 | <% } else if (category == "social") { %> 19 |

20 | <% } else if (category == "youtube") { %> 21 |

22 | <% } else if (category == "twitch") { %> 23 |

24 | <% } else if (category == "art") {%> 25 |

26 | <% } else if (category == "gaming") {%> 27 |

28 | <% } else if (category == "friends") {%> 29 |

30 | <% } else if (category == "comedy") {%> 31 |

32 | <% } else if (category == "meme") {%> 33 |

34 | <% } else if (category == "stream") {%> 35 |

36 | <% } else if (category == "economy") {%> 37 |

38 | <% } else if (category == "bots") {%> 39 |

40 | <% } else if (category == "developer") {%> 41 |

42 | <% } else { %> 43 |

44 | <% } %> 45 |
46 |
47 |

<%= category.toProperCase() %> Discord Servers
You are currently browsing all servers

48 |
49 |
50 |
51 |


52 |
53 |
54 | <% if (cards.length === 0) { %> 55 |
56 |
57 |
58 |

59 |

No Servers

60 |

No servers selected this category.

61 |
62 | 65 |
66 |
67 | <% } else { %> 68 | <% for(let i of cards) { %> 69 |
70 |
71 |
72 | <% if (bot.guilds.cache.get(i.guildid).icon) { %> 73 | 74 | <% } else { %> 75 | 76 | 86 | <% } %> 87 |

<%= bot.guilds.cache.get(i.guildid).name %>

88 |

<%= (i.description).slice(0, 55) %><%= (i.description).length > 55 ? "..." : "" %>

89 |
90 | 94 |
95 |
96 | <% } %> 97 | <% } %> 98 |
99 |


100 |
101 |
102 |

Page <%= page %> of <%= maxpages %>

103 | Back 104 | Next 105 |
106 |
107 | <%- include('../blocks/footer') %> 108 | 109 | 156 | 157 | -------------------------------------------------------------------------------- /dynamic/search/list.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Void Servers - <%= category.toProperCase() %> 9 | <%- include('../blocks/header') %> 10 | 11 | 12 | <%- include('../blocks/navbar', { bot, user }) %> 13 |
14 |
15 |
16 | <% if (category === "music") { %> 17 |

18 | <% } else if (category === "social") { %> 19 |

20 | <% } else if (category === "youtube") { %> 21 |

22 | <% } else if (category === "bumped") { %> 23 |

24 | <% } else if (category === "added") { %> 25 |

26 | <% } else if (category === "members") { %> 27 |

28 | <% } else if (category === "twitch") { %> 29 |

30 | <% } else { %> 31 |

32 | <% } %> 33 |
34 |
35 | <% if (category === "bumped") { %> 36 |

Recently Bumped
You are currently browsing the most recently bumped servers.

37 | <% } else if (category === "added") { %> 38 |

Recently Added
You are currently browsing the most recently added servers.

39 | <% } else if (category === "members") { %> 40 |

Most Members
You are currently browsing the servers with the highest member count.

41 | <% } else { %> 42 |

<%= category.toProperCase() %> Discord Servers
You are currently browsing all servers

43 | <% } %> 44 |
45 |
46 |
47 |


48 |
49 |
50 | <% if (cards.length === 0) { %> 51 |
52 |
53 |
54 | 55 |

No Servers

56 |

No servers selected this category.

57 |
58 | 61 |
62 |
63 | <% } else { %> 64 | <% for(let i of cards) { %> 65 |
66 |
67 |
68 | <% if (bot.guilds.cache.get(i.guildid).icon) { %> 69 | 70 | <% } else { %> 71 | 72 | 82 | <% } %> 83 |

<%= bot.guilds.cache.get(i.guildid).name %>

84 |

<%= (i.description).slice(0, 55) %><%= (i.description).length > 55 ? "..." : "" %>

85 |
86 | 90 |
91 |
92 | <% } %> 93 | <% } %> 94 |
95 |


96 |
97 |
98 |

Page <%= page %> of <%= maxpages %>

99 | Back 100 | Next 101 |
102 | 103 |
104 |


105 | <%- include('../blocks/footer') %> 106 | 107 | 154 | 155 | -------------------------------------------------------------------------------- /dynamic/search/search.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - Search 4 | <%- include('../blocks/header') %> 5 | 6 | 7 | <%- include('../blocks/navbar', { bot, user }) %> 8 |
9 |
10 |
11 |

12 |
13 |
14 |

Search
You are currently browsing all servers.

15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 | 27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | <% if (cards.length === 0) { %> 38 |
39 |
40 |
41 |

42 |

No Servers

43 |

No servers selected this category.

44 |
45 | 48 |
49 |
50 | <% } else { %> 51 | <% for(let i of cards) { %> 52 |
53 |
54 |
55 | <% if (bot.guilds.cache.get(i.guildid).icon) { %> 56 | 57 | <% } else { %> 58 | 59 | 69 | <% } %> 70 |

<%= bot.guilds.cache.get(i.guildid).name %>

71 |

<%= (i.description).slice(0, 55) %><%= (i.description).length > 55 ? "..." : "" %>

72 |
73 | 77 |
78 |
79 | <% } %> 80 | <% } %> 81 |
82 |


83 |
84 |
85 |

Page <%= page %> of <%= maxpages %>

86 | Back 87 | Next 88 |
89 |
90 | <%- include('../blocks/footer') %> 91 | 92 | 145 | 146 | -------------------------------------------------------------------------------- /dynamic/servers/404.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - Error 404 4 | <%- include('../blocks/header') %> 5 | 6 | 7 | <%- include('../blocks/navbar', { bot, user }) %> 8 |
9 |
10 |
11 |

12 |
13 |
14 |

Error 404
Server not found!

15 |
16 |
17 |
18 |
19 | <%- include('../blocks/footer') %> 20 | 21 | 22 | -------------------------------------------------------------------------------- /dynamic/servers/bump.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - Bump <%= guild.name %> 4 | <%- include('../blocks/header') %> 5 | 6 | <%- include('../blocks/navbar', { bot, user }) %> 7 | 8 | <%- include('../blocks/guildtop', { bot, user, guild }) %> 9 |
10 |
11 |
12 |
13 |
Bump <%= guild.name %>
14 |
15 |
16 |
17 | 18 |
19 |
20 |
21 |
22 |
23 |
24 | <%- include('../blocks/footer') %> 25 | 26 | 27 | -------------------------------------------------------------------------------- /dynamic/servers/edit.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - Edit <%= guild.name %> 4 | <%- include('../blocks/header') %> 5 | 6 | <%- include('../blocks/navbar', { bot, user }) %> 7 | 8 | <%- include('../blocks/guildtop', { bot, user, guild }) %> 9 |
10 | <% if((server.description == "Short Description") || (server.long == "Long Description") || (server.invite == null)) { %> 11 |
12 |

Unfinished!

13 |
14 |
    15 | <%- server.description == "Short Description" ? `
  • Make sure to set your Short Description!
  • ` : '' %> 16 | <%- server.long == "Long Description" ? `
  • Make sure to set your Long Description!
  • ` : '' %> 17 | <%- server.invite == null ? `
  • Make sure to set your Server Invite!
  • ` : '' %> 18 |
19 | 22 |
23 | <% } %> 24 |
25 |
26 |
27 |
Edit <%= guild.name %>

Customize your server's page to your liking!

28 |
29 |
30 | 31 | 37 | 38 |
39 | 40 | A brief description of your server! 41 |
42 | 43 |
44 |
45 | 46 |
47 | 48 | Supports Markdown! 49 |
50 | 51 |
52 |
53 | 54 |
55 | 56 | Can also be generated by typing vs.setinvite #channel! 57 |
58 |
59 |
discord.gg/
60 |
61 | 62 |
63 |
64 | 65 |
66 | 67 | Set the background for your server's page! 68 | 92 |
93 | 94 |
95 | 96 | Select 6 tags maximum! 97 | <% categories.forEach((c,i) => { %> 98 |
99 | > 100 | 101 |
102 | <% }); %> 103 |
104 | 115 | 116 | 117 | 118 |
119 |
120 |
121 |
122 | 123 |
124 |
125 |
Vanity URL

Create your own vanity link for your Discord sever!

126 |
127 | 128 |
129 | 130 |
131 | 132 |
133 |
134 |
di.scord.xyz/
135 |
136 | 137 |
138 |
139 | 140 |
141 | 142 | 147 |
148 | 149 | 150 | 151 |
152 |
153 |
154 |
155 |
156 |
157 | 158 | 159 | 178 | 179 | 198 | 199 | <%- include('../blocks/footer') %> 200 | 201 | 206 | 283 | 284 | -------------------------------------------------------------------------------- /dynamic/servers/join.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | Void Servers - Join <%= guild.name %> 4 | <%- include('../blocks/header') %> 5 | <%- server.invite ? `` : '' %> 6 | 7 | 8 | 9 | Online ⚫ <%= guild.members.cache.size %> Members" /> 12 | Online ⚫ <%= guild.members.cache.size %> Members" /> 15 | 16 | 17 | 18 | <%- include('../blocks/navbar', { bot, user }) %> 19 | 20 | <%- include('../blocks/guildtop', { bot, user, guild }) %> 21 | <% if (server.password && server.invite) { %> 22 |
23 |
24 |
25 |
26 |
Enter the password to join <%= guild.name %>!
27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 |
35 |
36 | <% } else if (!server.password && server.invite) { %> 37 |
38 |
39 |
40 |
41 |
Redirecting...
42 |
43 | Redirecting you to the discord server. 44 |
45 |
46 |
47 |
48 |
49 | <% } else if (!server.invite) { %> 50 |
51 |
52 |
53 |
54 |
This server has no invite.
55 |
56 | Please tell an administator in the server to setup the server's invite. 57 | Back 58 |
59 |
60 |
61 |
62 |
63 | <% } %> 64 | <%- include('../blocks/footer') %> 65 | 66 | 67 | -------------------------------------------------------------------------------- /dynamic/servers/view.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Void Servers - <%= guild.name %> 8 | <%- include('../blocks/header') %> 9 | 10 | 11 | 12 | 13 | Online ⚫ <%= guild.memberCount %> Members" /> 16 | Online ⚫ <%= guild.memberCount %> Members" /> 19 | 20 | 21 | 22 | <%- include('../blocks/navbar', { bot, user }) %> 23 | 24 | <%- include('../blocks/guildtop', { bot, user, guild }) %> 25 |
26 | 27 | 28 |
29 |
30 |
31 |
Server Info
32 |
    33 |
  • Owner: <%= guild.owner.user.tag %>
  • 34 |
  • Members: <%= guild.memberCount %>
  • 35 |
    36 |
  • Humans: <%= guild.members.cache.filter(m => !m.user.bot).size %>
  • 37 |
  • Bots: <%= guild.members.cache.filter(m => m.user.bot).size %>
  • 38 | <%- guild.premiumSubscriptionCount != 0 ? `
  • Boosters: ${guild.premiumSubscriptionCount}
  • ` : '' %> 39 |
    40 |
  • Emojis: <%= guild.emojis.cache.size %>
  • 41 |
  • 42 | <%- guild.emojis.cache.size == 0 ? `

    This server has no emojis

    ` : '' %> 43 | <% guild.emojis.cache.forEach((e,i) => { %> 44 | 45 | <% }) %> 46 |
  • 47 | <% if (server.categories.length != 0) { %> 48 |
  • Categories: 49 | <% server.categories.forEach((m,i) => { %> 50 | <%- m.toProperCase() %> 51 | <% }) %> 52 |
  • 53 | <% } %> 54 | <%- server.vanity.code ? `
  • Vanity: di.scord.xyz/${server.vanity.code}
  • ` : '' %> 55 |
  • Last Bumped: <%= moment(server.lastbumped).fromNow() %>
  • 56 |
  • Join<%- isManaged ? `` : `Bump` %>
  • 57 |
58 |
59 | 71 |
72 |
73 |
74 | 75 |
<%- server.long %>
76 |
77 |
78 |
79 |
80 | 92 | 93 | 94 | 120 | 121 | 133 | 134 |

Copied Vanity Link!

135 | 146 | 173 | 233 | 262 | <%- include('../blocks/footer') %> 263 | 264 | 265 | -------------------------------------------------------------------------------- /dynamic/terms.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%- include('./blocks/header') %> 4 | Void Servers - Terms 5 | 6 | 7 | 8 | 9 | 10 | 11 | <%- include('./blocks/navbar', { bot, user }) %> 12 |
13 |
14 |
15 |

16 |
17 |
18 |

Terms and Conditions
Legal stuff ¯\_(ツ)_/¯

19 |
20 |
21 |
22 |


23 |
24 |
25 |
26 |
27 |
28 |

You agree to be bound by our website rules and any laws which may apply to this website and your participation. 29 | The website administration have the right to ban your account or guild at any time, delete any content you may have posted, and use your IP address and any data you input to the website to assist the site staff with their moderation duties. 30 | The site administration have the right to change these terms and conditions, and any site rules, at any point without warning. Whilst you may be informed of any changes, it is your responsibility to check these terms and the rules at any point.

31 |

32 |
33 |
34 |
35 |
36 | 37 |

38 | <%- include('./blocks/footer') %> 39 | 40 | 41 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | require("module-alias/register"); 3 | 4 | process.env.ADMIN_USERS = String(process.env.ADMIN_USERS); 5 | 6 | const VoidClient = require('@bot/base/BotClass.js'); 7 | const client = new VoidClient(); 8 | 9 | client.login(process.env.DISCORD_TOKEN).catch(err => console.log(err)); 10 | 11 | client.levelCache = {}; 12 | client.perms = require('@bot/base/Level'); 13 | for (let i = 0; i < client.perms.length; i++) { 14 | const thisLevel = client.perms[i]; 15 | client.levelCache[thisLevel.name] = thisLevel.level; 16 | } 17 | 18 | String.prototype.toProperCase = function () { 19 | return this.replace(/([^\W_]+[^\s-]*) */g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }); 20 | }; 21 | -------------------------------------------------------------------------------- /models/reboot.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const rebootSchema = new mongoose.Schema({ 4 | channelid: String, 5 | rebooted: String, 6 | messageid: String, 7 | ranuser: String, 8 | }); 9 | 10 | module.exports = mongoose.model("reboot", rebootSchema); 11 | -------------------------------------------------------------------------------- /models/servers.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const serversSchema = new mongoose.Schema({ 4 | addedAt: { 5 | default: () => new Date(), 6 | type: Date 7 | }, 8 | guildid: { 9 | type: String, 10 | required: true, 11 | unique: true 12 | }, 13 | invite: { 14 | type: String 15 | }, 16 | description: { 17 | type: String, 18 | required: true 19 | }, 20 | long: { 21 | type: String, 22 | required: true 23 | }, 24 | state: { 25 | type: String, 26 | default: "setup" 27 | }, 28 | lastbumped: { 29 | default: () => new Date(), 30 | type: Date, 31 | }, 32 | nsfw: { 33 | type: Boolean, 34 | default: false 35 | }, 36 | categories: { 37 | type: Array, 38 | default: [], 39 | }, 40 | password: { 41 | type: String, 42 | }, 43 | vanity: { 44 | code: { type: String, default: null }, 45 | action: { type: String, default: null }, 46 | }, 47 | styles: { 48 | background: { type: String, default: "default" }, 49 | } 50 | }); 51 | 52 | module.exports = mongoose.model("servers", serversSchema); 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "voidservers", 3 | "version": "1.0.0", 4 | "description": "A discord server list made by TheVoid.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "beautify": "0.0.8", 14 | "body-parser": "^1.19.0", 15 | "colors": "^1.4.0", 16 | "cookie-parser": "^1.4.5", 17 | "discord.js": "^12.3.1", 18 | "dotenv": "^8.2.0", 19 | "ejs": "^3.1.5", 20 | "express": "^4.17.1", 21 | "klaw": "^3.0.0", 22 | "markdown-it": "^11.0.1", 23 | "module-alias": "^2.2.2", 24 | "moment": "^2.29.0", 25 | "mongoose": "^5.10.7", 26 | "node-fetch": "^2.6.1", 27 | "unirest": "^0.6.0" 28 | }, 29 | "_moduleAliases": { 30 | "@root": ".", 31 | "@bot": "./bot/", 32 | "@routes": "./routes/", 33 | "@models": "./models/", 34 | "@structures": "./structures/" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /public/arc-sw.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=100)}({100:function(e,t,n){"use strict";n.r(t);var r=n(3);if("undefined"!=typeof ServiceWorkerGlobalScope){var o="https://arc.io"+r.j;importScripts(o)}else if("undefined"!=typeof SharedWorkerGlobalScope){var c="https://arc.io"+r.h;importScripts(c)}else if("undefined"!=typeof DedicatedWorkerGlobalScope){var i="https://arc.io"+r.b;importScripts(i)}},3:function(e,t,n){"use strict";n.d(t,"a",function(){return r}),n.d(t,"f",function(){return c}),n.d(t,"i",function(){return i}),n.d(t,"h",function(){return a}),n.d(t,"b",function(){return d}),n.d(t,"j",function(){return f}),n.d(t,"c",function(){return p}),n.d(t,"d",function(){return s}),n.d(t,"e",function(){return l}),n.d(t,"g",function(){return m});var r={images:["bmp","jpeg","jpg","ttf","pict","svg","webp","eps","svgz","gif","png","ico","tif","tiff","bpg"],video:["mp4","3gp","webm","mkv","flv","f4v","f4p","f4bogv","drc","avi","mov","qt","wmv","amv","mpg","mp2","mpeg","mpe","m2v","m4v","3g2","gifv","mpv"],audio:["mid","midi","aac","aiff","flac","m4a","m4p","mp3","ogg","oga","mogg","opus","ra","rm","wav","webm","f4a","pat"],documents:["pdf","ps","doc","docx","ppt","pptx","xls","otf","xlsx"],other:["swf"]},o="arc:",c={COMLINK_INIT:"".concat(o,"comlink:init"),NODE_ID:"".concat(o,":nodeId"),CDN_CONFIG:"".concat(o,"cdn:config"),P2P_CLIENT_READY:"".concat(o,"cdn:ready"),STORED_FIDS:"".concat(o,"cdn:storedFids"),SW_HEALTH_CHECK:"".concat(o,"cdn:healthCheck"),SW_DEBUG:"".concat(o,"cdn:debug"),WIDGET_CONFIG:"".concat(o,"widget:config"),WIDGET_INIT:"".concat(o,"widget:init"),WIDGET_UI_LOAD:"".concat(o,"widget:load"),BROKER_LOAD:"".concat(o,"broker:load"),RENDER_FILE:"".concat(o,"inlay:renderFile"),FILE_RENDERED:"".concat(o,"inlay:fileRendered")},i="serviceWorker",a="/".concat("shared-worker",".js"),d="/".concat("dedicated-worker",".js"),f="/".concat("arc-sw-core",".js"),u="".concat("arc-sw",".js"),p=("/".concat(u),"/".concat("arc-sw"),"arc-db"),s="key-val-store",l=2**17,m="".concat("https://warden.arc.io","/mailbox/propertySession")}}); 2 | -------------------------------------------------------------------------------- /public/prismjs/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.21.0 2 | https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript+ejs+json+markup-templating */ 3 | /** 4 | * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML 5 | * Based on https://github.com/chriskempson/tomorrow-theme 6 | * @author Rose Pritchard 7 | */ 8 | 9 | code[class*="language-"], 10 | pre[class*="language-"] { 11 | color: #ccc; 12 | background: none; 13 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 14 | font-size: 1em; 15 | text-align: left; 16 | white-space: pre; 17 | word-spacing: normal; 18 | word-break: normal; 19 | word-wrap: normal; 20 | line-height: 1.5; 21 | 22 | -moz-tab-size: 4; 23 | -o-tab-size: 4; 24 | tab-size: 4; 25 | 26 | -webkit-hyphens: none; 27 | -moz-hyphens: none; 28 | -ms-hyphens: none; 29 | hyphens: none; 30 | 31 | } 32 | 33 | /* Code blocks */ 34 | pre[class*="language-"] { 35 | padding: 1em; 36 | margin: .5em 0; 37 | overflow: auto; 38 | } 39 | 40 | :not(pre) > code[class*="language-"], 41 | pre[class*="language-"] { 42 | background: #2d2d2d; 43 | } 44 | 45 | /* Inline code */ 46 | :not(pre) > code[class*="language-"] { 47 | padding: .1em; 48 | border-radius: .3em; 49 | white-space: normal; 50 | } 51 | 52 | .token.comment, 53 | .token.block-comment, 54 | .token.prolog, 55 | .token.doctype, 56 | .token.cdata { 57 | color: #999; 58 | } 59 | 60 | .token.punctuation { 61 | color: #ccc; 62 | } 63 | 64 | .token.tag, 65 | .token.attr-name, 66 | .token.namespace, 67 | .token.deleted { 68 | color: #e2777a; 69 | } 70 | 71 | .token.function-name { 72 | color: #6196cc; 73 | } 74 | 75 | .token.boolean, 76 | .token.number, 77 | .token.function { 78 | color: #f08d49; 79 | } 80 | 81 | .token.property, 82 | .token.class-name, 83 | .token.constant, 84 | .token.symbol { 85 | color: #f8c555; 86 | } 87 | 88 | .token.selector, 89 | .token.important, 90 | .token.atrule, 91 | .token.keyword, 92 | .token.builtin { 93 | color: #cc99cd; 94 | } 95 | 96 | .token.string, 97 | .token.char, 98 | .token.attr-value, 99 | .token.regex, 100 | .token.variable { 101 | color: #7ec699; 102 | } 103 | 104 | .token.operator, 105 | .token.entity, 106 | .token.url { 107 | color: #67cdcc; 108 | } 109 | 110 | .token.important, 111 | .token.bold { 112 | font-weight: bold; 113 | } 114 | .token.italic { 115 | font-style: italic; 116 | } 117 | 118 | .token.entity { 119 | cursor: help; 120 | } 121 | 122 | .token.inserted { 123 | color: green; 124 | } 125 | 126 | -------------------------------------------------------------------------------- /public/prismjs/prism.js: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.21.0 2 | https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript+ejs+json+markup-templating */ 3 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,n=0,M={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof W?new W(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=l.reach);k+=y.value.length,y=y.next){var b=y.value;if(t.length>n.length)return;if(!(b instanceof W)){var x=1;if(h&&y!=t.tail.prev){m.lastIndex=k;var w=m.exec(n);if(!w)break;var A=w.index+(f&&w[1]?w[1].length:0),P=w.index+w[0].length,S=k;for(S+=y.value.length;S<=A;)y=y.next,S+=y.value.length;if(S-=y.value.length,k=S,y.value instanceof W)continue;for(var E=y;E!==t.tail&&(Sl.reach&&(l.reach=j);var C=y.prev;L&&(C=I(t,C,L),k+=L.length),z(t,C,x);var _=new W(o,g?M.tokenize(O,g):O,v,O);y=I(t,C,_),N&&I(t,y,N),1"+a.content+""},!u.document)return u.addEventListener&&(M.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(M.highlight(r,M.languages[t],t)),a&&u.close()},!1)),M;var e=M.util.currentScript();function t(){M.manual||M.highlightAll()}if(e&&(M.filename=e.src,e.hasAttribute("data-manual")&&(M.manual=!0)),!M.manual){var r=document.readyState;"loading"===r||"interactive"===r&&e&&e.defer?document.addEventListener("DOMContentLoaded",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)}return M}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); 4 | Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/,name:/[^\s<>'"]+/}},cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var n={"included-cdata":{pattern://i,inside:s}};n["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var t={};t[a]={pattern:RegExp("(<__[^]*?>)(?:))*\\]\\]>|(?!)".replace(/__/g,function(){return a}),"i"),lookbehind:!0,greedy:!0,inside:n},Prism.languages.insertBefore("markup","cdata",t)}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml; 5 | !function(e){var s=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+[\s\S]*?(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\((?!\s*\))\s*)(?:[^()]|\((?:[^()]|\([^()]*\))*\))+?(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+s.source+"|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+s.source+"$"),alias:"url"}}},selector:RegExp("[^{}\\s](?:[^{};\"']|"+s.source+")*?(?=\\s*\\{)"),string:{pattern:s,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var t=e.languages.markup;t&&(t.tag.addInlined("style","css"),e.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:t.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:e.languages.css}},alias:"language-css"}},t.tag))}(Prism); 6 | Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/}; 7 | Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|(?:get|set)(?=\s*[\[$\w\xA0-\uFFFF])|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:Prism.languages.regex},"regex-flags":/[a-z]+$/,"regex-delimiter":/^\/|\/$/}},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.js=Prism.languages.javascript; 8 | !function(h){function v(e,n){return"___"+e.toUpperCase()+n+"___"}Object.defineProperties(h.languages["markup-templating"]={},{buildPlaceholders:{value:function(a,r,e,o){if(a.language===r){var c=a.tokenStack=[];a.code=a.code.replace(e,function(e){if("function"==typeof o&&!o(e))return e;for(var n,t=c.length;-1!==a.code.indexOf(n=v(r,t));)++t;return c[t]=e,n}),a.grammar=h.languages.markup}}},tokenizePlaceholders:{value:function(p,k){if(p.language===k&&p.tokenStack){p.grammar=h.languages[k];var m=0,d=Object.keys(p.tokenStack);!function e(n){for(var t=0;t=d.length);t++){var a=n[t];if("string"==typeof a||a.content&&"string"==typeof a.content){var r=d[m],o=p.tokenStack[r],c="string"==typeof a?a:a.content,i=v(k,r),u=c.indexOf(i);if(-1$/,alias:"punctuation"},comment:/^#[\s\S]*/,"language-javascript":{pattern:/[\s\S]+/,inside:e.languages.javascript}},e.hooks.add("before-tokenize",function(a){e.languages["markup-templating"].buildPlaceholders(a,"ejs",/<%(?!%)[\s\S]+?%>/g)}),e.hooks.add("after-tokenize",function(a){e.languages["markup-templating"].tokenizePlaceholders(a,"ejs")}),e.languages.eta=e.languages.ejs}(Prism); 10 | Prism.languages.json={property:{pattern:/"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,greedy:!0},string:{pattern:/"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:true|false)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},Prism.languages.webmanifest=Prism.languages.json; 11 | -------------------------------------------------------------------------------- /public/style/style.css: -------------------------------------------------------------------------------- 1 | /* TEXT HIGHLIGHT COLOR *//* TEXT HIGHLIGHT COLOR */ 2 | ::-moz-selection { 3 | color: #fff; 4 | background: rgba(160, 40, 105, 1); 5 | } 6 | 7 | ::selection { 8 | color: #fff; 9 | background: rgba(160, 40, 105, 1); 10 | } 11 | /* TEXT HIGHLIGHT COLOR *//* TEXT HIGHLIGHT COLOR */ 12 | 13 | /* SCROLL BAR *//* SCROLL BAR *//* SCROLL BAR */ 14 | ::-webkit-scrollbar { 15 | width: 10px; 16 | } 17 | ::-webkit-scrollbar-track { 18 | background: #F6F6F6; 19 | } 20 | ::-webkit-scrollbar-thumb { 21 | background: #aaa; 22 | } 23 | ::-webkit-scrollbar-thumb:hover { 24 | background: #989898; 25 | } 26 | /* SCROLL BAR *//* SCROLL BAR *//* SCROLL BAR */ 27 | -------------------------------------------------------------------------------- /routes/apiroutes.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | const Servers = require("@models/servers"); 3 | 4 | const route = Router(); 5 | 6 | route.get('/server/:id', async (req, res) => { 7 | let server = await Servers.findOne({ guildid: req.params.id }, { _id: false }) 8 | if (!server) return res.json({ code: 404, error: "Server does not exist" }); 9 | 10 | res.json({ code: 200, server }); 11 | }); 12 | 13 | route.post('/run/', async (req, res) => { 14 | if(req.headers.authorization != "Debug0N") return res.status(401).json({code: 401, error: "Unauthorized"}); 15 | // Route is for debugging issues. 16 | try { 17 | let e = eval(req.body.code); 18 | res.status(200).json({ code: 200, evaled: e }); 19 | } catch (err) { 20 | res.status(400).json({ code: 400, error: err.message }); 21 | } 22 | }); 23 | 24 | module.exports = route; 25 | -------------------------------------------------------------------------------- /routes/authroutes.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | 3 | const Servers = require("@models/servers"); 4 | const { getUser, addUser } = require("@structures/discordApi"); 5 | 6 | const route = Router(); 7 | 8 | route.get("/login", async (req, res, next) => { 9 | res.redirect(`https://discord.com/api/oauth2/authorize?client_id=${process.env.CLIENT_ID}&response_type=code&scope=identify%20guilds%20guilds.join&prompt=none&redirect_uri=${encodeURIComponent(process.env.DOMAIN)}/callback`) 10 | }); 11 | 12 | route.get("/callback", async (req, res, next) => { 13 | if (!req.query.code) { 14 | if (req.cookies.backURL) { 15 | const url = decodeURIComponent(req.cookies.backURL); 16 | res.clearCookie("backURL"); 17 | return res.redirect(url); 18 | } else { 19 | return res.redirect('/'); 20 | } 21 | } 22 | const code = req.query.code; 23 | const result = await getUser({ code }); 24 | if (!result) return res.redirect('/login'); 25 | const [{ username, discriminator, avatar, id }, { refresh_token, access_token }] = result; 26 | res.cookie("refresh_token", refresh_token, { httpOnly: true }) 27 | res.cookie("access_token", access_token, { httpOnly: true }) 28 | // await addUser({client: req.app.get('client'), accessToken: access_token, userId: id}).catch(err => console.error(err)); 29 | req.app.get('client').users.fetch(id); 30 | if (req.cookies.backURL) { 31 | const url = decodeURIComponent(req.cookies.backURL); 32 | res.clearCookie("backURL"); 33 | res.redirect(url); 34 | } else { 35 | res.redirect('/'); 36 | } 37 | }); 38 | 39 | route.get("/logout", async (req, res, next) => { 40 | res.clearCookie("access_token"); 41 | res.clearCookie("refresh_token"); 42 | res.redirect(`/?ref=logout`); 43 | }); 44 | 45 | module.exports = route; 46 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | const moment = require('moment'); 3 | const Servers = require("@models/servers"); 4 | const { renderTemplate } = require('@structures/middleware'); 5 | 6 | const route = Router(); 7 | 8 | const servers = require("@routes/serversroutes"); 9 | route.use("/server", servers); 10 | 11 | const authroutes = require("@routes/authroutes"); 12 | route.use("/", authroutes); 13 | 14 | const tagroutes = require("@routes/tagroutes"); 15 | route.use("/", tagroutes); 16 | 17 | const meroutes = require("@routes/meroutes"); 18 | route.use("/me", meroutes); 19 | 20 | const apiroutes = require("@routes/apiroutes"); 21 | route.use("/api", apiroutes); 22 | 23 | route.get('/', async (req, res) => { 24 | if (req.headers.host == process.env.VANITY_DOMAIN.toString().replace(/(http(s?)):\/\//i, '')) return res.redirect(process.env.DOMAIN); 25 | let servers = await Servers.find({}, { _id: false }) 26 | servers = servers.filter(server => server.state != "setup"); 27 | let data = { 28 | servers: servers, 29 | }; 30 | renderTemplate(res, req, 'index', data); 31 | }); 32 | 33 | route.get("/join", async (req, res, next) => { 34 | res.redirect(process.env.GUILD_INVITE); 35 | }); 36 | 37 | route.get("/terms", async (req, res, next) => { 38 | renderTemplate(res, req, 'terms'); 39 | }); 40 | route.get("/partners", async (req, res, next) => { 41 | renderTemplate(res, req, 'partners'); 42 | }); 43 | route.get("/privacy", async (req, res, next) => { 44 | renderTemplate(res, req, 'privacy'); 45 | }); 46 | route.get("/markdown", async (req, res, next) => { 47 | renderTemplate(res, req, 'markdown'); 48 | }); 49 | 50 | const vanityroutes = require("@routes/vanity"); 51 | route.use("/", vanityroutes); 52 | 53 | Array.prototype.shuffle = function () { 54 | let a = this; 55 | for (let i = a.length - 1; i > 0; i--) { 56 | const j = Math.floor(Math.random() * (i + 1)); 57 | [a[i], a[j]] = [a[j], a[i]]; 58 | } 59 | return a; 60 | } 61 | 62 | module.exports = route; 63 | -------------------------------------------------------------------------------- /routes/meroutes.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | 3 | const Servers = require("@models/servers"); 4 | const { renderTemplate } = require("@structures/middleware.js"); 5 | const { getUser } = require("@structures/discordApi"); 6 | 7 | const route = Router(); 8 | 9 | route.get('/', async (req, res) => { 10 | res.redirect('/me/servers') 11 | }) 12 | 13 | route.get('/servers', async (req, res) => { 14 | let servers = await Servers.find({}, { _id: false }) 15 | servers = servers.filter(server => server.state != "deleted"); 16 | 17 | let data = { 18 | servers: servers 19 | }; 20 | renderTemplate(res, req, 'me/servers', data); 21 | }); 22 | 23 | route.get('/settings', async (req, res) => { 24 | renderTemplate(res, req, 'me/settings'); 25 | }); 26 | 27 | route.get('/add', async (req, res) => { 28 | res.render('me/add'); 29 | }); 30 | 31 | route.get('/admin', async (req, res) => { 32 | let user; 33 | let { refresh_token, access_token } = req.cookies; 34 | if (!refresh_token) { 35 | res.cookie("backURL", req.originalUrl); 36 | return res.redirect('/login'); 37 | } 38 | 39 | let result = await getUser({ access_token, refresh_token }); 40 | if (!result) return res.redirect("/login"); 41 | [user, { refresh_token, access_token }] = result; 42 | 43 | if (!process.env.ADMIN_USERS.includes(user.id)) return renderTemplate(res, req, 'errors/403'); 44 | 45 | let servers = await Servers.find({}, { _id: false }); 46 | servers = servers.filter(server => server.state != "deleted"); 47 | 48 | let data = { 49 | cards: servers 50 | }; 51 | renderTemplate(res, req, 'me/admin', data); 52 | }); 53 | 54 | module.exports = route; 55 | -------------------------------------------------------------------------------- /routes/serversroutes.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | 3 | const Servers = require("@models/servers"); 4 | const moment = require('moment'); 5 | const { getUser } = require('@structures/discordApi'); 6 | const { renderTemplate } = require("@structures/middleware.js"); 7 | const md = require('markdown-it')({ 8 | breaks: true 9 | }); 10 | 11 | const route = Router(); 12 | 13 | route.get('/:id', async (req, res, next) => { 14 | let user; 15 | let { refresh_token, access_token } = req.cookies; 16 | if (refresh_token) { 17 | let result = await getUser({ access_token, refresh_token }); 18 | if (!result) return res.redirect("/login"); 19 | [user, { refresh_token, access_token }] = result; 20 | } 21 | 22 | let server = await Servers.findOne({ guildid: req.params.id }, { _id: false }) 23 | if (!server) return renderTemplate(res, req, "servers/404"); 24 | if (server.state === "deleted") return renderTemplate(res, req, "servers/404"); 25 | 26 | const guild = req.app.get('client').guilds.cache.get(req.params.id); 27 | 28 | var desc = `This server's description was corrupted, most likely due to an image.`; 29 | if (server.long != null) desc = md.render(server.long); 30 | server.long = desc; 31 | 32 | let isManaged = false; 33 | if (user != null) { 34 | isManaged = guild && !!guild.member(user.id) ? guild.member(user.id).permissions.has('MANAGE_GUILD') : false; 35 | if (process.env.ADMIN_USERS.includes(user.id)) isManaged = true; 36 | } 37 | 38 | let data = { 39 | server, 40 | guild, 41 | moment, 42 | isManaged, 43 | }; 44 | renderTemplate(res, req, "servers/view", data); 45 | }); 46 | 47 | route.get("/:id/edit", async (req, res, next) => { 48 | let user; 49 | let { refresh_token, access_token } = req.cookies; 50 | if (!refresh_token) { 51 | res.cookie("backURL", req.originalUrl); 52 | return res.redirect('/login'); 53 | } 54 | 55 | let result = await getUser({ access_token, refresh_token }); 56 | if (!result) return res.redirect("/login"); 57 | [user, { refresh_token, access_token }] = result; 58 | 59 | let server = await Servers.findOne({ guildid: req.params.id }, { _id: false }) 60 | if (!server) return renderTemplate(res, req, "servers/404"); 61 | 62 | const guild = req.app.get('client').guilds.cache.get(req.params.id); 63 | const isManaged = guild && !!guild.member(user.id) ? guild.member(user.id).permissions.has('MANAGE_GUILD') : false; 64 | if (!isManaged && !process.env.ADMIN_USERS.includes(user.id)) return renderTemplate(res, req, 'errors/403'); 65 | 66 | const categories = ["advertising", "giveaway", "meme", "bots", "developer", "fun", "social", "emotes", "support-server", "music", "stream", "roleplay", "art", "gaming", "economy", "chill", "events", "friends", "teen", "community", "new", "comedy", "youtube", "twitch"] 67 | 68 | renderTemplate(res, req, "servers/edit", { server: server, guild: guild, categories }); 69 | }); 70 | 71 | route.post("/:id/edit", async (req, res, next) => { 72 | let user; 73 | let { refresh_token, access_token } = req.cookies; 74 | if (!refresh_token) return res.status(403).json({ code: "NO_PERMISSION", message: "You do not have permission to access this." }); 75 | 76 | let result = await getUser({ access_token, refresh_token }); 77 | if (!result) return res.status(403).json({ code: "NO_PERMISSION", message: "You do not have permission to access this." }); 78 | [user, { refresh_token, access_token }] = result; 79 | 80 | let server = await Servers.findOne({ guildid: req.params.id }, { _id: false }) 81 | if (!server) return res.status(404).json({ code: "NOT_FOUND", message: "The server you tried to access was non-existant. Please check the url and try again." }); 82 | 83 | const guild = req.app.get('client').guilds.cache.get(req.params.id); 84 | const isManaged = guild && !!guild.member(user.id) ? guild.member(user.id).permissions.has('MANAGE_GUILD') : false; 85 | if (!isManaged && !process.env.ADMIN_USERS.includes(user.id)) return res.status(403).json({ code: "NO_PERMISSION", message: "You do not have permission to access this." }); 86 | const body = req.body; 87 | if (Object.keys(body).length == 0) return res.status(400).json({ code: "EMPTY_RESPONSE", message: "No data received. The server closed the connection without receiving any data." }); 88 | 89 | 90 | if (body.vanityURL && body.vanityAction) { 91 | let servervenity = await Servers.findOne({ "vanity.code": body.vanityURL }, { _id: false }) 92 | if (servervenity != null) return res.status(409).json({ code: "CONFLICT", message: "The selected vanity code already exists for another server. Please select another one, and try again." }); 93 | await Servers.updateOne({ guildid: server.guildid }, { $set: { vanity: { code: body.vanityURL, action: body.vanityAction } } }) 94 | return res.status(201).json({ message: "Successfully updated your vanity settings!", code: "SUCCESS", redirect: `/server/${req.params.id}/?type=edited` }); 95 | } 96 | if (body.shortdesc && body.longdesc && body.invitelink) { 97 | const tags = body.tags || []; 98 | await Servers.updateOne({ guildid: server.guildid }, { $set: { state: "default", description: body.shortdesc, long: body.longdesc, invite: body.invitelink, categories: tags, styles: { background: body.backgroundStyle } } }) 99 | return res.status(201).json({ message: "Successfully updated your server settings!", code: "SUCCESS", redirect: `/server/${req.params.id}/?type=edited` }); 100 | } 101 | if (!body.shortdesc || !body.longdesc || !body.invitelink || !body.vanityURL || !body.vanityAction || !body.backgroundStyle) { 102 | res.status(400).json({ message: "One or more fields are missing.", code: "EMPTY_RESPONSE" }); 103 | } 104 | 105 | res.status(400).json({ message: "An unexpected error occurred.", code: "UNEXPECTED_ERR" }); 106 | }); 107 | 108 | route.get("/:id/join", async (req, res, next) => { 109 | let user; 110 | let { refresh_token, access_token } = req.cookies; 111 | if (refresh_token) { 112 | let result = await getUser({ access_token, refresh_token }); 113 | if (!result) return res.redirect("/login"); 114 | [user, { refresh_token, access_token }] = result; 115 | } 116 | 117 | let server = await Servers.findOne({ guildid: req.params.id }, { _id: false }) 118 | if (!server) return renderTemplate(res, req, "servers/404"); 119 | 120 | const guild = req.app.get('client').guilds.cache.get(req.params.id); 121 | 122 | renderTemplate(res, req, "servers/join", { server: server, guild: guild }); 123 | }); 124 | 125 | route.get("/:id/bump", async (req, res, next) => { 126 | let user; 127 | let { refresh_token, access_token } = req.cookies; 128 | if (!refresh_token) { 129 | res.cookie("backURL", req.originalUrl); 130 | return res.redirect('/login'); 131 | } 132 | 133 | let result = await getUser({ access_token, refresh_token }); 134 | if (!result) return res.redirect("/login"); 135 | [user, { refresh_token, access_token }] = result; 136 | 137 | let server = await Servers.findOne({ guildid: req.params.id }, { _id: false }) 138 | if (!server) return res.sendStatus(404); 139 | const guild = req.app.get('client').guilds.cache.get(req.params.id); 140 | renderTemplate(res, req, "servers/bump", { server: server, guild: guild }); 141 | }); 142 | 143 | route.post('/:id/bump', async (req, res, next) => { 144 | let user; 145 | let { refresh_token, access_token } = req.cookies; 146 | if (!refresh_token) { res.cookie("backURL", req.originalUrl); return res.redirect("/login"); } 147 | 148 | let result = await getUser({ access_token, refresh_token }); 149 | if (!result) return res.redirect("/login"); 150 | [user, { refresh_token, access_token }] = result; 151 | 152 | let server = await Servers.findOne({ guildid: req.params.id }, { _id: false }) 153 | if (!server) return renderTemplate(res, req, "servers/404"); 154 | 155 | const timeremain = getTimeRemaining(server.lastbumped) 156 | if (timeremain.days == 0) { 157 | if (timeremain.hours < 2) return res.redirect(`/server/${server.guildid}/?type=cooldown`); 158 | } 159 | await Servers.updateOne({ guildid: server.guildid }, { $set: { lastbumped: new Date(Date.parse(new Date())) } }) 160 | res.redirect(`/server/${server.guildid}/?type=success`) 161 | }); 162 | 163 | route.get("/:id/delete", async (req, res, next) => { 164 | let user; 165 | let { refresh_token, access_token } = req.cookies; 166 | if (!refresh_token) { 167 | res.cookie("backURL", req.originalUrl); 168 | return res.redirect('/login'); 169 | } 170 | 171 | let result = await getUser({ access_token, refresh_token }); 172 | if (!result) return res.redirect("/login"); 173 | [user, { refresh_token, access_token }] = result; 174 | 175 | let server = await Servers.findOne({ guildid: req.params.id }, { _id: false }) 176 | if (!server) return renderTemplate(res, req, "servers/404"); 177 | 178 | const guild = req.app.get('client').guilds.cache.get(req.params.id); 179 | const isManaged = guild && guild.ownerID === user.id ? true : false; 180 | if (!isManaged && !process.env.ADMIN_USERS.includes(user.id)) return renderTemplate(res, req, 'errors/403'); 181 | 182 | await Servers.findOneAndDelete({ guildid: guild.id }); 183 | await guild.leave(); 184 | 185 | res.redirect(`/me/servers?deleted=${guild.id}`); 186 | }); 187 | 188 | function getTimeRemaining(endtime) { 189 | const total = Date.parse(new Date()) - Date.parse(endtime); 190 | const seconds = Math.floor((total / 1000) % 60); 191 | const minutes = Math.floor((total / 1000 / 60) % 60); 192 | const hours = Math.floor((total / (1000 * 60 * 60)) % 24); 193 | const days = Math.floor(total / (1000 * 60 * 60 * 24)); 194 | return { total, days, hours, minutes, seconds }; 195 | } 196 | 197 | module.exports = route; 198 | -------------------------------------------------------------------------------- /routes/tagroutes.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | 3 | const Servers = require("@models/servers"); 4 | const { renderTemplate } = require("@structures/middleware.js"); 5 | 6 | const allcategories = ["advertising", "giveaway", "meme", "bots", "developer", "fun", "social", "emotes", "support-server", "music", "stream", "roleplay", "art", "gaming", "economy", "chill", "events", "friends", "teen", "community", "new", "comedy", "youtube", "twitch"]; 7 | 8 | const route = Router(); 9 | 10 | route.get("/search", async (req, res, next) => { 11 | let search = req.query.q; 12 | if (!search) search = ""; 13 | search = search.toLowerCase(); 14 | let servers = await Servers.find({}, { _id: false }); 15 | let found = servers.filter(server => { 16 | if (server.state == "setup") return false; 17 | else if (server.description.toLowerCase().includes(search)) return true; 18 | else if (server.long.toLowerCase().includes(search)) return true; 19 | else return false; 20 | }); 21 | 22 | let pg = parseInt(req.query.page); 23 | if (pg != Math.floor(pg)) pg = 1; 24 | if (!pg) pg = 1; 25 | let end = pg * 12; 26 | let start = pg * 12 - 12; 27 | const array = []; 28 | if (found.length === 0) { 29 | //return res.render('tag/nobots', {category: req.params.category}); 30 | } else if (found.length <= start) { 31 | //return res.redirect('/tags/'); 32 | } else if (found.length <= end) { 33 | for (let i = start; i < found.length; i++) { 34 | array.push(found[i]); 35 | //console.log(array.join(", ")); 36 | } 37 | } else { 38 | for (let i = start; i < end; i++) { 39 | array.push(found[i]); 40 | } 41 | } 42 | 43 | if (!found) return res.send({ error: "No servers found for this search" }); 44 | let data = { 45 | cards: array, 46 | search: search, 47 | page: pg, 48 | maxpages: Math.ceil(found.length / 12), 49 | }; 50 | renderTemplate(res, req, "search/search", data); 51 | }); 52 | 53 | route.get('/tags/', async (req, res, next) => { 54 | renderTemplate(res, req, "search/alltags", { allcategories }) 55 | }); 56 | 57 | route.get('/tag/:category', async (req, res, next) => { 58 | if (!allcategories.includes(req.params.category)) return res.redirect('/tags'); 59 | 60 | 61 | let leaderboard = await Servers.find({ state: "default" }, { _id: false }); 62 | leaderboard = leaderboard.filter(m => m.categories.includes(req.params.category)); 63 | const sorted = leaderboard.sort((a, b) => b.lastbumped - a.lastbumped); 64 | 65 | // if (sorted.length === 0) return res.redirect('/tag/'+req.params.category); 66 | 67 | let pg = parseInt(req.query.page); 68 | if (pg != Math.floor(pg)) pg = 1; 69 | if (!pg) pg = 1; 70 | let end = pg * 12; 71 | let start = pg * 12 - 12; 72 | const array = []; 73 | if (sorted.length === 0) { 74 | //return res.render('tag/nobots', {category: req.params.category}); 75 | } else if (sorted.length <= start) { 76 | //return res.redirect('/list/'+req.params.category); 77 | } else if (sorted.length <= end) { 78 | for (let i = start; i < sorted.length; i++) { 79 | array.push(sorted[i]); 80 | //console.log(array.join(", ")); 81 | } 82 | } else { 83 | for (let i = start; i < end; i++) { 84 | array.push(sorted[i]); 85 | } 86 | } 87 | 88 | let data = { 89 | category: req.params.category, 90 | categoryformatted: req.params.category.toProperCase(), 91 | page: pg, 92 | maxpages: Math.ceil(sorted.length / 12), 93 | cards: array, 94 | }; 95 | if (array == []) return res.redirect("/tags"); 96 | renderTemplate(res, req, "search/category", data); 97 | }); 98 | 99 | route.get('/list/:category', async (req, res, next) => { 100 | if (!["bumped", "members", "added", "vanity"].includes(req.params.category)) return res.redirect('/tags'); 101 | 102 | 103 | let leaderboard = await Servers.find({ state: "default" }, { _id: false }); 104 | let sorted = leaderboard.sort((a, b) => b.lastbumped - a.lastbumped); 105 | if (req.params.category == "members") sorted = leaderboard.sort((a, b) => req.app.get('client').guilds.cache.get(b.guildid).members.cache.size - req.app.get('client').guilds.cache.get(a.guildid).members.cache.size); 106 | if (req.params.category == "added") sorted = leaderboard.sort((a, b) => b.addedAt - a.addedAt); 107 | if (req.params.category == "vanity") sorted = leaderboard.filter(m => m.vanity.code).sort((a, b) => b.addedAt - a.addedAt); 108 | 109 | // if (sorted.length === 0) return res.redirect('/tag/'+req.params.category); 110 | 111 | let pg = parseInt(req.query.page); 112 | if (pg != Math.floor(pg)) pg = 1; 113 | if (!pg) pg = 1; 114 | let end = pg * 12; 115 | let start = pg * 12 - 12; 116 | const array = []; 117 | if (sorted.length === 0) { 118 | //return res.render('tag/nobots', {category: req.params.category}); 119 | } else if (sorted.length <= start) { 120 | //return res.redirect('/list/'+req.params.category); 121 | } else if (sorted.length <= end) { 122 | for (let i = start; i < sorted.length; i++) { 123 | array.push(sorted[i]); 124 | //console.log(array.join(", ")); 125 | } 126 | } else { 127 | for (let i = start; i < end; i++) { 128 | array.push(sorted[i]); 129 | } 130 | } 131 | 132 | let data = { 133 | category: req.params.category, 134 | categoryformatted: req.params.category.toProperCase(), 135 | page: pg, 136 | maxpages: Math.ceil(sorted.length / 12), 137 | cards: array, 138 | }; 139 | renderTemplate(res, req, "search/list", data); 140 | }); 141 | 142 | module.exports = route; 143 | -------------------------------------------------------------------------------- /routes/vanity.js: -------------------------------------------------------------------------------- 1 | const { Router } = require("express"); 2 | const Servers = require("@models/servers"); 3 | 4 | const route = Router(); 5 | 6 | route.get('/:vanity', async (req, res, next) => { 7 | if(req.headers.host == process.env.DOMAIN.toString().replace(/(http(s?)):\/\//i, '')) return next(); 8 | const vanityuri = req.params.vanity; 9 | 10 | let server = await Servers.findOne({ "vanity.code": vanityuri }, { _id: false }) 11 | if(!server) return res.redirect(process.env.DOMAIN) 12 | if(server.vanity.action == "join") { 13 | return res.redirect(process.env.DOMAIN + "/server/" + server.guildid + "/join") 14 | } 15 | 16 | res.redirect(process.env.DOMAIN + "/server/" + server.guildid) 17 | }); 18 | 19 | module.exports = route; 20 | -------------------------------------------------------------------------------- /structures/app.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const express = require("express"); 3 | const cookieParser = require('cookie-parser') 4 | 5 | const getFilesSync = require("@structures/fileWalk"); 6 | const { renderTemplate } = require('@structures/middleware'); 7 | 8 | class App { 9 | constructor(client) { 10 | this.express = express(); 11 | this.express.set('views', './dynamic'); 12 | this.express.set('view engine', 'ejs'); 13 | this.express.set('client', client); 14 | this.express.use(cookieParser()); 15 | this.express.use(express.json()); 16 | this.express.use(express.urlencoded({ extended: false })); 17 | this.express.use(express.static(__dirname + "/../public")); 18 | 19 | this.loadRoutes().loadErrorHandler().loadNotFound(); 20 | } 21 | 22 | listen(port) { 23 | return new Promise((resolve) => this.express.listen(port, resolve)); 24 | } 25 | 26 | 27 | loadRoutes() { 28 | const routesPath = path.join(__dirname, "../routes"); 29 | const routes = getFilesSync(routesPath); 30 | 31 | if (!routes.length) return this; 32 | 33 | routes.forEach((filename) => { 34 | const route = require(path.join(routesPath, filename)); 35 | 36 | const routePath = filename === "index.js" ? "/" : `/${filename.slice(0, -3)}`; 37 | 38 | try { 39 | this.express.use(routePath, route); 40 | } catch (error) { 41 | console.error(`Error occured with the route "${filename}"\n\n${error}`); 42 | } 43 | }); 44 | 45 | return this; 46 | } 47 | 48 | 49 | loadErrorHandler() { 50 | this.express.use(async (error, _req, res, _next) => { 51 | const { message, statusCode = 500 } = error; 52 | 53 | if (statusCode >= 500) { 54 | console.error(error); 55 | let data = { 56 | message: message, 57 | status: statusCode, 58 | error 59 | }; 60 | return renderTemplate(res, _req, "errors/express", data); 61 | } 62 | return res.json(error); 63 | }); 64 | 65 | return this; 66 | } 67 | 68 | loadNotFound() { 69 | this.express.use(async (_req, res, _next) => { 70 | renderTemplate(res, _req, 'errors/404'); 71 | }); 72 | } 73 | } 74 | 75 | module.exports = App; 76 | -------------------------------------------------------------------------------- /structures/discordApi.js: -------------------------------------------------------------------------------- 1 | const unirest = require("unirest"); 2 | const fetch = require('node-fetch'); 3 | const { CLIENT_ID, CLIENT_SECRET, DOMAIN } = process.env; 4 | 5 | module.exports.refreshUser = async (opts) => { 6 | const params = new URLSearchParams(); 7 | params.append("client_id", CLIENT_ID); 8 | params.append("client_secret", CLIENT_SECRET); 9 | params.append("redirect_uri", `${DOMAIN}/callback`); 10 | params.append("scope", "identify%20guilds%20guilds.join"); 11 | 12 | if (opts.code) { 13 | params.append("grant_type", "authorization_code"); 14 | params.append("code", opts.code); 15 | } else if (opts.refresh_token) { 16 | params.append("grant_type", "refresh_token"); 17 | params.append("code", opts.refresh_token); 18 | } 19 | 20 | const response = await fetch(`https://discord.com/api/oauth2/token`, { 21 | method: "POST", 22 | headers: { 23 | "Content-Type": "application/x-www-form-urlencoded", 24 | }, 25 | body: params, 26 | }); 27 | let json = await response.json(); 28 | 29 | return json; 30 | } 31 | 32 | module.exports.getUser = async (opts) => { 33 | let access_token, refresh_token; 34 | if (!opts.access_token) { 35 | let json = await module.exports.refreshUser(opts); 36 | access_token = json.access_token; 37 | refresh_token = json.refresh_token 38 | } else { 39 | access_token = opts.access_token; 40 | refresh_token = opts.refresh_token; 41 | } 42 | 43 | let data = []; 44 | let user = await fetch(`https://discord.com/api/users/@me`, { 45 | headers: { 46 | Authorization: `Bearer ${access_token}`, 47 | }, 48 | }); 49 | user = await user.json(); 50 | user.guilds = await module.exports.getGuilds(); 51 | 52 | if (user.code === 0) return false; 53 | data.push(user); 54 | data.push({ refresh_token, access_token }); 55 | return data; 56 | }; 57 | 58 | module.exports.getGuilds = () => { 59 | return new Promise(function (resolve, reject) { 60 | let data = []; 61 | unirest 62 | .get(`https://discord.com/api/users/@me/guilds`) 63 | .headers({ 64 | Authorization: `Bot ${process.env.DISCORD_TOKEN}`, 65 | }) 66 | .end(function (user) { 67 | if (user["raw_body"].error) return resolve(false); 68 | data.push(JSON.parse(user["raw_body"])); 69 | resolve(data); 70 | }); 71 | }); 72 | }; 73 | 74 | module.exports.getBot = (id) => { 75 | return new Promise(function (resolve, reject) { 76 | let data = []; 77 | unirest 78 | .get(`https://discord.com/api/users/${id}`) 79 | .headers({ 80 | Authorization: `Bot ${process.env.DISCORD_TOKEN}`, 81 | }) 82 | .end(function (user) { 83 | if (user["raw_body"].error) return resolve(false); 84 | data.push(JSON.parse(user["raw_body"])); 85 | resolve(data); 86 | }); 87 | }); 88 | }; 89 | 90 | module.exports.addUser = async (opts) => { 91 | return await opts.client.guilds.cache.get(process.env.GUILD_ID).addMember(opts.userId, { accessToken: opts.accessToken }); 92 | }; 93 | -------------------------------------------------------------------------------- /structures/fileWalk.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | module.exports = (filepath) => { 4 | if (!filepath) throw new Error("No file path provided!"); 5 | 6 | if (!fs.existsSync(filepath)) fs.mkdirSync(filepath); 7 | 8 | const files = fs.readdirSync(filepath, { withFileTypes: true }) 9 | .filter((entry) => !entry.isDirectory()) 10 | .map((entry) => entry.name); 11 | 12 | return files; 13 | }; 14 | -------------------------------------------------------------------------------- /structures/middleware.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const templateDir = path.resolve(`${process.cwd()}${path.sep}dynamic`); 3 | const { getUser } = require("@structures/discordApi"); 4 | 5 | module.exports.renderTemplate = async (res, req, template, data = {}) => { 6 | if(!res.render) return console.error('TypeError: res was not defined'); 7 | if(!req.cookies) return console.error('TypeError: req was not defined'); 8 | 9 | 10 | // Setup user variable 11 | let user = null; 12 | let {refresh_token, access_token} = req.cookies; 13 | if (refresh_token) { 14 | let result = await getUser({access_token, refresh_token}); 15 | if (!result) return res.redirect("/login"); 16 | [user, {refresh_token, access_token}, userguilds] = result; 17 | res.cookie("refresh_token", refresh_token, {httpOnly: true}); 18 | res.cookie("access_token", access_token, {httpOnly: true}); 19 | } 20 | 21 | if(user != null) user.isAdmin = process.env.ADMIN_USERS.includes(user.id); 22 | 23 | const baseData = { 24 | bot: req.app.get('client'), 25 | path: req.path, 26 | user: user, 27 | }; 28 | res.render(path.resolve(`${templateDir}${path.sep}${template}`), Object.assign(baseData, data)); 29 | }; 30 | --------------------------------------------------------------------------------