-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
455 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
const url = require("url"); | ||
const path = require("path"); | ||
const express = require("express"); | ||
const passport = require("passport"); | ||
const session = require("express-session"); | ||
const Strategy = require("passport-discord").Strategy; | ||
const config = require("../config"); | ||
const ejs = require("ejs"); | ||
const bodyParser = require("body-parser"); | ||
const Discord = require("discord.js"); | ||
const GuildSettings = require("./../models/guild"); | ||
|
||
const app = express(); | ||
const MemoryStore = require("memorystore")(session); | ||
|
||
module.exports = async (client) => { | ||
const dataDir = path.resolve(`${process.cwd()}${path.sep}dashboard`); | ||
const templateDir = path.resolve(`${dataDir}${path.sep}templates`); | ||
|
||
passport.serializeUser((user, done) => done(null, user)); | ||
passport.deserializeUser((obj, done) => done(null, obj)); | ||
|
||
var callbackUrl; | ||
var domain; | ||
|
||
try { | ||
const domainUrl = new URL(config.domain); | ||
domain = { | ||
host: domainUrl.hostname, | ||
protocol: domainUrl.protocol | ||
}; | ||
} catch (e) { | ||
console.log(e); | ||
throw new TypeError("Invalid domain specific in the config file."); | ||
} | ||
|
||
if (config.usingCustomDomain) { | ||
callbackUrl = `${domain.protocol}//${domain.host}/callback` | ||
} else { | ||
callbackUrl = `${domain.protocol}//${domain.host}${config.port == 80 ? "" : `:${config.port}`}/callback`; | ||
} | ||
|
||
passport.use(new Strategy({ | ||
clientID: config.id, | ||
clientSecret: config.clientSecret, | ||
callbackURL: callbackUrl, | ||
scope: ["identify", "guilds"] | ||
}, | ||
(accessToken, refreshToken, profile, done) => { | ||
process.nextTick(() => done(null, profile)); | ||
})); | ||
|
||
app.use(session({ | ||
store: new MemoryStore({ checkPeriod: 86400000 }), | ||
secret: "#@%#&^$^$%@$^$&%#$%@#$%$^%&$%^#$%@#$%#E%#%@$FEErfgr3g#%GT%536c53cc6%5%tv%4y4hrgrggrgrgf4n", | ||
resave: false, | ||
saveUninitialized: false, | ||
})); | ||
|
||
app.use(passport.initialize()); | ||
app.use(passport.session()); | ||
|
||
app.locals.domain = config.domain.split("//")[1]; | ||
|
||
app.engine("html", ejs.renderFile); | ||
app.set("view engine", "html"); | ||
|
||
app.use(bodyParser.json()); | ||
app.use(bodyParser.urlencoded({ | ||
extended: true | ||
})); | ||
|
||
app.use("/", express.static(path.resolve(`${dataDir}${path.sep}assets`))); | ||
|
||
const renderTemplate = (res, req, template, data = {}) => { | ||
const baseData = { | ||
bot: client, | ||
path: req.path, | ||
user: req.isAuthenticated() ? req.user : null | ||
}; | ||
res.render(path.resolve(`${templateDir}${path.sep}${template}`), Object.assign(baseData, data)); | ||
}; | ||
|
||
const checkAuth = (req, res, next) => { | ||
if (req.isAuthenticated()) return next(); | ||
req.session.backURL = req.url; | ||
res.redirect("/login"); | ||
} | ||
|
||
app.get("/login", (req, res, next) => { | ||
if (req.session.backURL) { | ||
req.session.backURL = req.session.backURL; | ||
} else if (req.headers.referer) { | ||
const parsed = url.parse(req.headers.referer); | ||
if (parsed.hostname === app.locals.domain) { | ||
req.session.backURL = parsed.path; | ||
} | ||
} else { | ||
req.session.backURL = "/"; | ||
} | ||
next(); | ||
}, | ||
passport.authenticate("discord")); | ||
|
||
app.get("/callback", passport.authenticate("discord", { failureRedirect: "/" }), (req, res) => { | ||
if (req.session.backURL) { | ||
const url = req.session.backURL; | ||
req.session.backURL = null; | ||
res.redirect(url); | ||
} else { | ||
res.redirect("/"); | ||
} | ||
}); | ||
|
||
app.get("/logout", function (req, res) { | ||
req.session.destroy(() => { | ||
req.logout(); | ||
res.redirect("/"); | ||
}); | ||
}); | ||
|
||
app.get("/", (req, res) => { | ||
renderTemplate(res, req, "index.ejs"); | ||
}); | ||
|
||
app.get("/dashboard", checkAuth, (req, res) => { | ||
renderTemplate(res, req, "dashboard.ejs", { perms: Discord.Permissions }); | ||
}); | ||
|
||
app.get("/dashboard/:guildID", checkAuth, async (req, res) => { | ||
const guild = client.guilds.cache.get(req.params.guildID); | ||
if (!guild) return res.redirect("/dashboard"); | ||
const member = guild.members.cache.get(req.user.id); | ||
if(!member){ | ||
try{ await guild.members.fetch(); | ||
member = guild.members.cache.get(req.user.id); | ||
} catch (err) { console.error(`Couldn't fetch the members of ${guild.id}: ${err}`); }} | ||
if (!member) return res.redirect("/dashboard"); | ||
if (!member.permissions.has("MANAGE_GUILD")) return res.redirect("/dashboard"); | ||
|
||
var storedSettings = await GuildSettings.findOne({ guildID: guild.id }); | ||
if (!storedSettings) { | ||
const newSettings = new GuildSettings({ | ||
guildID: guild.id | ||
}); | ||
await newSettings.save().catch(()=>{}); | ||
storedSettings = await GuildSettings.findOne({ guildID: guild.id }); | ||
} | ||
|
||
renderTemplate(res, req, "settings.ejs", { guild, settings: storedSettings, alert: null }); | ||
}); | ||
|
||
app.post("/dashboard/:guildID", checkAuth, async (req, res) => { | ||
const guild = client.guilds.cache.get(req.params.guildID); | ||
if (!guild) return res.redirect("/dashboard"); | ||
const member = guild.members.cache.get(req.user.id); | ||
if (!member) return res.redirect("/dashboard"); | ||
if (!member.permissions.has("MANAGE_GUILD")) return res.redirect("/dashboard"); | ||
var storedSettings = await GuildSettings.findOne({ guildID: guild.id }); | ||
if (!storedSettings) { | ||
const newSettings = new GuildSettings({ | ||
guildID: guild.id | ||
}); | ||
await newSettings.save().catch(() => {}); | ||
storedSettings = await GuildSettings.findOne({ guildID: guild.id }); | ||
} | ||
|
||
storedSettings.prefix = req.body.prefix; | ||
storedSettings.welcomeChannel = req.body.welcomeChannel; | ||
storedSettings.xpChannel = req.body.xpChannel; | ||
await storedSettings.save().catch(() => {}); | ||
|
||
renderTemplate(res, req, "settings.ejs", { guild, settings: storedSettings, alert: "Your settings have been saved." }); | ||
}); | ||
|
||
app.listen(config.port, null, null, () => console.log(`Dashboard is up and running on port ${config.port}.`)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<%- include("partials/header", { bot, user, path, title: "Select server" }) %> | ||
|
||
<div style="display: flex; flex-wrap: wrap; justify-content: center;"> | ||
<% user.guilds.forEach(guild => { | ||
const permsOnGuild = new perms(guild.permissions); | ||
if(!permsOnGuild.has("MANAGE_GUILD")) return; | ||
%> | ||
<div class="card" style="max-width: 18rem; margin: 2rem; min-width: 10em;"> | ||
<%- guild.icon ? `<img src="https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}" class="card-img-top" style="max-width: 18rem;">` : "" %> | ||
<div class="card-body"> | ||
<h5 class="card-title"><%= guild.name %></h5> | ||
<% if (bot.guilds.cache.get(guild.id)) { %> | ||
<p class="card-text">Edit <%= guild.name %>'s settings via the dashboard by clicking the button below.</p> | ||
<a href="/dashboard/<%- guild.id %>" class="btn btn-success text-white">Edit Settings</a> | ||
<% } else { %> | ||
<p class="card-text">Invite the bot to <%= guild.name %> in order to their this server's settings via the dashboard by clicking the button below.</p> | ||
<a href="<%= `https://discordapp.com/oauth2/authorize?client_id=${bot.user.id}&scope=bot&guild_id=${guild.id}&response_type=code&redirect_uri=${encodeURIComponent(`${bot.config.domain}${bot.config.port == 80 ? "" : `:${bot.config.port}`}/callback`)}` %>" class="btn btn-primary text-white">Invite Bot</a> | ||
<% } %> | ||
</div> | ||
</div> | ||
<% | ||
}); | ||
%> | ||
</div> | ||
|
||
<%- include("partials/footer") %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<%- include("partials/header", { bot, user, path, title: "Home" }) %> | ||
|
||
<div class="container-sm center" style="margin-top: 25px;"> | ||
<div class="d-grid gap-2 col-6 mx-auto"> | ||
<h2>Welcome to Nobara's Dashboard!</h2> | ||
<p>🔨🔩 | Un bot discord franco-anglais avec plusieurs fonctionnalités à savoir Economy, Music, XP, Moderation, ...</p> | ||
<p>A big shotout to <a href="https://github.com/MrAugu/simple-discordjs-dashboard">MrAugu</a>for the dashboard base.</p> | ||
<a class="btn btn-secondary text-white" href="/dashboard">Dashboard</a> | ||
<a class="btn btn-primary text-white" href="https://github.com/SonMaxime/Nobara.JS">GitHub</a> | ||
<a class="btn btn-warning" href="">Discord Server (soon)</a> | ||
</div> | ||
</div> | ||
|
||
<%- include("partials/footer") %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title><%= title %></title> | ||
<link href="/bootstrap.min.css" rel="stylesheet"> | ||
<link rel="stylesheet" href="/style.css"> | ||
</head> | ||
<body> | ||
<nav class="navbar navbar-expand-lg navbar-light bg-light"> | ||
<div class="container-fluid"> | ||
<a class="navbar-brand" href="#">Nobara Dashboard</a> | ||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation"> | ||
<span class="navbar-toggler-icon"></span> | ||
</button> | ||
<div class="collapse navbar-collapse" id="navbarText"> | ||
<ul class="navbar-nav me-auto mb-2 mb-lg-0"> | ||
<li class="nav-item"> | ||
<a class="nav-link active" aria-current="page" href="/">Home</a> | ||
</li> | ||
<li class="nav-item"> | ||
<a class="nav-link" href="/dashboard">Dashboard</a> | ||
</li> | ||
<li class="nav-item"> | ||
<a class="nav-link" href="https://www.twitter.com/SonMaxime_">Twitter</a> | ||
</li> | ||
</ul> | ||
<ul class="navbar-nav"> | ||
<% if (user) { %> | ||
<li class="nav-item dropdown"> | ||
<a class="nav-link dropdown-toggle" href="#" id="navbarScrollingDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false"> | ||
Logged in as <%= user.username %>#<%= user.discriminator %> | ||
</a> | ||
<ul class="dropdown-menu" aria-labelledby="navbarScrollingDropdown"> | ||
<li><a class="dropdown-item" href="/dashboard">Dashboard</a></li> | ||
<li><hr class="dropdown-divider"></li> | ||
<li><a class="dropdown-item" href="/logout">Logout</a></li> | ||
</ul> | ||
</li> | ||
</li> | ||
<% } else { %> | ||
<li class="nav-item"><a href="/login" class="nav-link">Login</a></li> | ||
<% } %> | ||
</ul> | ||
</div> | ||
</div> | ||
</nav> | ||
<!-- <% if (user) { %> | ||
<p>Logged in as <%= user.username %>#<%= user.discriminator %>.</p> | ||
<a href="/logout">Logout</a> | ||
<% } else { %> | ||
<a type="button" href="/login">Login</a><br> | ||
<% } %> | ||
<% if(user && title === "Home") { %> | ||
<a type="button" href="/dashboard">Back to dashboard</a><br> | ||
<% } %> | ||
<%- title === "Dashboard" ? "" : "<hr>" %> --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<%- include("partials/header", { bot, user, path, title: `Settings | ${guild.name}` }) %> | ||
|
||
<div class="container-sm center" style="margin-top: 30px;"> | ||
<div class="d-grid gap-2 col-4 mx-auto"> | ||
<% if (alert) { %> | ||
<div class="alert alert-success" role="alert"> | ||
<%= alert %> | ||
</div> | ||
<% } %> | ||
<h1><%= guild.name %></h1> | ||
<hr> | ||
<form method="POST"> | ||
<p class="h5" style="margin-bottom: 0.5rem; margin-top: 10px;">Prefix:</p> | ||
<p style="font-style: italic;" class="disabled">The prefix that is added to discord messages in order to invoke commands.</p> | ||
<input type="text" class="form-control" name="prefix" value="<%= settings.prefix %>" placeholder="You're prefix."> | ||
|
||
<p class="h5" style="margin-bottom: 0.5rem; margin-top: 10px;">Welcome channel:</p> | ||
<p style="font-style: italic;" class="disabled">The welcome channel is the ID of the channel where all you're members will be welcomed.</p> | ||
<input type="text" class="form-control" name="welcomeChannel" value="<%= settings.welcomeChannel %>" placeholder="You're welcome channel ID."> | ||
|
||
<p class="h5" style="margin-bottom: 0.5rem; margin-top: 10px;">Level UP channel:</p> | ||
<p style="font-style: italic;" class="disabled">The Level UP channel is the ID of the channel where all you're members will be GG'd.</p> | ||
<input type="text" class="form-control" name="xpChannel" value="<%= settings.xpChannel %>" placeholder="You're Level UP channel ID."> | ||
|
||
<br><button type="submit" class="btn btn-secondary text-white">Save Settings</button> | ||
</form> | ||
</div> | ||
</div> | ||
|
||
<%- include("partials/footer") %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.