├── .gitignore ├── .gitattributes ├── router.js ├── config.json.example ├── routes ├── index.js └── discord.js ├── views ├── partials │ └── navbar.ejs └── index.ejs ├── app.js ├── package.json ├── static └── stylesheet.css └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | config.json -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /router.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | // '/' 3 | app.use('/', require('./routes/index')); 4 | 5 | // '/authorize' 6 | app.use('/authorize', require('./routes/discord')); 7 | } -------------------------------------------------------------------------------- /config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "port": 3000, 3 | 4 | "clientId": "", 5 | "clientSecret": "", 6 | "scopes": ["identify", "guilds"], 7 | "redirectUri": "http://localhost:3000/authorize/callback" 8 | } -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router(); 2 | 3 | router.get('/', (req, res) => { 4 | res.render('index', { pageTitle: 'Dashboard', user: req.session.user || null }); 5 | }); 6 | 7 | module.exports = router; -------------------------------------------------------------------------------- /views/partials/navbar.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | 4 | let port = require('./config.json').port || 3000; 5 | app.set('port', port); 6 | 7 | const session = require('express-session'); 8 | 9 | app.set('view engine', 'ejs'); 10 | app.use(express.static('static')); 11 | app.use(session({ 12 | secret: '48738924783748273742398747238', 13 | resave: false, 14 | saveUninitialized: false, 15 | expires: 604800000, 16 | })); 17 | require('./router')(app); 18 | 19 | app.listen(port, () => console.info(`Listening on port ${port}`)); -------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%- pageTitle %> 9 | 10 | 11 | 12 | 13 | <%- include('partials/navbar.ejs') %> 14 | 15 |
16 |

Welcome

17 |

To get started, login by clicking Login on the navbar, then go to the servers page and choose a server to manage.

18 |
19 | 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discord.js-dashboard", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/caelinj/discord.js-dashboard.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/caelinj/discord.js-dashboard/issues" 19 | }, 20 | "homepage": "https://github.com/caelinj/discord.js-dashboard#readme", 21 | "dependencies": { 22 | "ejs": "^2.6.1", 23 | "express": "^4.16.3", 24 | "express-session": "^1.15.6", 25 | "form-data": "^2.3.2", 26 | "node-fetch": "^2.2.0", 27 | "uid-safe": "^2.1.5" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /static/stylesheet.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Roboto:300,500'); 2 | 3 | body { 4 | background: #2C2F33; 5 | margin: 0 0; 6 | padding: 0 0; 7 | } 8 | 9 | .page-content { 10 | padding: 4px 42px; 11 | } 12 | 13 | .page-content h1 { margin-bottom: -10px; } 14 | 15 | h1, h2, h3, h4, h5, h6 { 16 | font-family: 'Roboto', sans-serif; 17 | font-weight: 500; 18 | color: #ffffff; 19 | } 20 | 21 | p, a { 22 | font-family: 'Roboto', sans-serif; 23 | font-weight: 300; 24 | color: #ffffff; 25 | } 26 | 27 | .navbar { 28 | background: #23272A; 29 | padding: 21px 42px; 30 | } 31 | 32 | .navbar a { 33 | transition: .25s ease; 34 | color: #ffffff; 35 | text-decoration: none; 36 | } 37 | 38 | .navbar a:hover { 39 | color: #7792f3; 40 | } 41 | 42 | .navbar a:not(:last-child) { 43 | margin-right: 12px; 44 | } 45 | 46 | .navbar .right { 47 | float: right; 48 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 caelinj 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /routes/discord.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router(); 2 | 3 | const { clientId, clientSecret, scopes, redirectUri } = require('../config.json'); 4 | const fetch = require('node-fetch'); 5 | const FormData = require('form-data'); 6 | 7 | const forceAuth = (req, res, next) => { 8 | if (!req.session.user) return res.redirect('/authorize') 9 | else return next(); 10 | } 11 | 12 | router.get('/', (req, res) => { 13 | if (req.session.user) return res.redirect('/'); 14 | 15 | const authorizeUrl = `https://discordapp.com/api/oauth2/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${scopes.join('%20')}`; 16 | res.redirect(authorizeUrl); 17 | }); 18 | 19 | router.get('/callback', (req, res) => { 20 | if (req.session.user) return res.redirect('/'); 21 | 22 | const accessCode = req.query.code; 23 | if (!accessCode) throw new Error('No access code returned frm Discord'); 24 | 25 | const data = new FormData(); 26 | data.append('client_id', clientId); 27 | data.append('client_secret', clientSecret); 28 | data.append('grant_type', 'authorization_code'); 29 | data.append('redirect_uri', redirectUri); 30 | data.append('scope', scopes.join(' ')); 31 | data.append('code', accessCode); 32 | 33 | fetch('https://discordapp.com/api/oauth2/token', { 34 | method: 'POST', 35 | body: data 36 | }) 37 | .then(res => res.json()) 38 | .then(response => { 39 | fetch('https://discordapp.com/api/users/@me', { 40 | method: 'GET', 41 | headers: { 42 | authorization: `${response.token_type} ${response.access_token}` 43 | }, 44 | }) 45 | .then(res2 => res2.json()) 46 | .then(userResponse => { 47 | userResponse.tag = `${userResponse.username}#${userResponse.discriminator}`; 48 | userResponse.avatarURL = userResponse.avatar ? `https://cdn.discordapp.com/avatars/${userResponse.id}/${userResponse.avatar}.png?size=1024` : null; 49 | 50 | req.session.user = userResponse; 51 | res.redirect('/'); 52 | }); 53 | }); 54 | }); 55 | 56 | router.get('/logout', forceAuth, (req, res) => { 57 | req.session.destroy(); 58 | }); 59 | 60 | module.exports = router; --------------------------------------------------------------------------------