App.get() not working with express.js

Hello. I’m trying to create an API that connects to my bot’s dashboard, but when I try to access the api page, it doesn’t work. I’ve created the dashboard with express.js, and all the other methods are firing. Here’s the one that doesn’t work:

app.get("/api/:action", async function(req, res) {
  let apicodes = await db.fetch(`apicodes`)
  console.log('1')
  let action = req.params.action
  if (apicodes) {
    console.log('2')
	if (apicodes.keys.includes(req.query.key)) {
	  if (apicodes.secrets.includes(req.query.secret)) {
	  if (action) {
		if (action === 'check') {
			let check = await db.fetch(`gban_${req.params.userid}`)
			if (check) {
				res.send(check)
			} else {
				res.send('Not Banned')
			}
		} else {
			if (action === 'ban') {
				let user = req.query.userid,
					reason = req.query.reason,
					evidence = req.query.evidence,
					moderator = req.query.moderator,
					requester = req.query.botid;
				let request = {type: 'ban', userID: user, reason: reason, evidence: evidence, moderator: moderator, botid: requester, status: 'Not checked'}
				await db.set(`banrequests_${requester}`)
			} else {
				if (action === 'unban') {
					let user = req.query.userid,
						reason = req.query.reason,
						moderator = req.query.moderator,
						requester = req.query.botid;
					let request = {type: 'unban', userID: user, reason: reason, moderator: moderator, botid: requester, status: 'Not checked'}
					await db.set(`banrequests_${requester}`)
				} else {
					if (action === 'editban') {
						if (req.query.reason) {
							let user = req.query.userid,
								reason = req.query.reason,
								moderator = req.query.moderator,
								requester = req.query.botid;
							let request = {type: 'editban', userID: user, reason: reason, moderator: moderator, botid: requester, status: 'Not checked'}
							await db.set(`banrequests_${requester}`)
						} else {
							if (req.query.evidence) {
								let user = req.query.userid,
									evidence = req.query.evidence,
									moderator = req.query.moderator,
									requester = req.query.botid;
								let request = {type: 'editban', userID: user, evidence: evidence, moderator: moderator, botid: requester, status: 'Not checked'}
								await db.set(`banrequests_${requester}`)
							}
						}
					} else {
						if (action === 'requests') {
							let requester = req.query.botid
							let requests = await db.fetch(`banrequests_${requester}`)
							if (requests) {
								res.send(requests)
								} else {
									res.send('No requests.')
							}
						} else {
							if (action === 'checkcon') {
								res.status(200).send('OK.')
							}
						}
					}
				}
			}
		}
	  } else {
      console.log('2')
      res.send('Invalid API call method.')}//.status(401)
	 } else res.send('Invalid API auth secret.')//.status(401)
	} else res.send('Invalid API auth key.')//.status(401)
 } else res.send('API code check broken')//.status(401)
  });

Can someone please help me?

Can you please show some logs?

Its a bit hard to read with so many nested if’s that really belong on the same level.

It seems that most of your action handlers don’t send any response to the incoming request in express. By “not working” do you mean it seems nothing happens on the client side?

@TheBigerGamer I saw it at first sight. I was hoping you would too. Use “ifelse” instead of “else”

Oh gosh, there’s too many if-else statements, @chessebuilderman can point out where it is?

I saw this in only saw this and didn’t see ifelse statements

I didn’t saw it. And still can’t see it. And it don’t even triggers. It doesn’t run the code. I was expecting to have 1 in the console because of that console.log('1'), but it doesn’t show that.

And there’s no log. The console doesn’t show any error. Only shows this: <hidden ip> - - [26/Feb/2020:11:17:49 +0000] "GET /favicon.ico HTTP/1.1" 304 - "https://myprojectdomain/api" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"

EDIT: I tried to add

app.get("/test", function (req, res) {
res.send("test")
})

And it doesn’t work

Did you add app.listen?

Change else to ifelse

    .listen(client.config.dashboard.port, function() {
      client.log(
        "log",
        `Dashboard running on port ${client.config.dashboard.port}`,
        "INFO"
      );
    })

And wdym by changing else to ifelse?

The port has to be the port assigned to your glitch project. Try process.env.PORT

Where ever it says else, change it to ifelse

The port has been configurated by another way. And I already have a website setted up. I just can’t add more pages, for some reason.

And @chessebuilderman you mean:

if (something) {} ifelse {}

? Because that doesn’t seem to work. But I think I’ll use the switch statement.
And my problem isn’t the organisation of the code, but that the event app.get("/api/:action", async function(req, res) {…}) isn’t firing.

EDIT: These can cause any problem with APIs?

app.engine("html", require("ejs").renderFile);
  app.set("view engine", "html");

It would be

if (...) {...} else if (...) {...}

Oh. OK. And what about the other question?

Yes. What port are you using?

  1. And all the other pages of the website work fine! But why the events I add don’t work?

Just make a separate address for each action.

An example of how to send a response … see the last line

if (action === 'ban') {
    let user = req.query.userid,
        reason = req.query.reason,
        evidence = req.query.evidence,
        moderator = req.query.moderator,
        requester = req.query.botid;
    let request = { type: 'ban', userID: user, reason: reason, evidence: evidence, moderator: moderator, botid: requester, status: 'Not checked' }
    await db.set(`banrequests_${requester}`)
    res.send('banned') // try adding this line
}

Have formatted the code for you, do not disgrace yourself

const getAPICodes = async () => await db.fetch(`apicodes`);
const getBannedStatus = async id => await db.fetch(`gban_${id}`);
const banRequest = async (req, type) => {
  const { userid: userId } = req.params;
  const { reason, evidence, moderator, botid: requester } = req.query;
  const request = {
    type: type || "ban",
    userID: userId,
    reason: reason,
    evidence: evidence,
    moderator: moderator,
    botid: requester,
    status: "Not checked"
  };
  return await db.set(`banrequests_${requester}`);
};

const actionHandler = async (req, res) => {
  const apiCodes = await getAPICodes();
  const { keys: apiCodesKeys, secrets: apiCodesSecrets } = apiCodes;
  const { action, userid: userId } = req.params;
  const { key, secret } = req.query;
  const passingState =
    apiCodesKeys.includes(key) && apiCodesSecrets.includes(secret);

  if (!action || !apiCodes || !passingState) return res.status(401).json({
    message: "Unauthorized",
    code: 401
  })

  switch (action) {
    case "check": {
      const check = getBannedStatus(userId);

      if (check) {
        res.send(check);
      } else {
        res.send("Not Banned");
      }
    }

    case "ban": {
      res.json(banRequest(req, "ban"));
    }

    case "unban": {
      res.json(banRequest(req, "unban"));
    }

    case "editban": {
      res.json(banRequest(req, "editban"));
    }

    case "requests": {
      res.json(await db.get(`banrequests_${req.paramd.botid}`));
    }

    case "checkon": {
      res.sendStatus(200);
    }
  }
};

app.get("/api/:action", async (req, res) => await actionHandler(req, res));
1 Like

Thank you for formating the code. But for some reason, it still doesn’t fire the event :confused:

Man, you’re stuck on a website starter project. Add package.json and add express and etc. Double check you have node in your container

I have it. Do you want to see the entire package.json? I imported a bot I created from github, reinstalled the packages and everything went good for a lot of time, and the rest still works. Idk why this isn’t working.

Well, then, I think, your module is not being imported by any other. Check that your file is required by some other module

@TheBigerGamer do you have a package.json file?

If your code is in a different file than your main file…

//Other file
exports.run = async (app, db, ...) {
     //your code goes here
};
//Main file
const beingCalled = require("path/to/file.js").run(app, db, ...);

In this way, you aren’t creating a new app and your code is actually being called.

Have this in events/ready.js: require('../modules/dashboard')(client);

Yes I have:

  "name": "global-protector",
  "version": "8.3.1",
  "description": "My first Discord bot made in Discord.js",
  "main": "bot.js",
  "dependencies": {
    "bufferutil": "^3.0.2",
    "child_process": "^1.0.2",
    "discord.js": "^11.2.1",
    "djs-collection-persistent": "^0.1.4",
    "ejs": "^2.5.7",
    "enmap": "^0.4.2",
    "enmap-level": "^1.0.0",
    "express": "^4.16.2",
    "express-session": "^1.15.6",
    "helmet": "^3.9.0",
    "marked": "^0.3.6",
    "moment": "^2.19.1",
    "moment-duration-format": "^1.3.0",
    "morgan": "^1.9.0",
    "passport": "^0.4.0",
    "passport-discord": "^0.1.2",
    "path": "^0.12.7",
    "process-nextick-args": "^1.0.7",
    "rebuild": "^0.1.2",
    "url": "^0.11.0",
    "util-deprecate": "^1.0.2",
    "showdown": "^1.8.1",
    "cheerio": "^0.22.0",
    "node-bypasser": "^1.8.0",
    "simple-youtube-api": "^5.0.0",
    "ytdl-core": "^0.18.5",
    "opusscript": "^0.0.6",
    "prism-media": "^0.0.2",
    "isgd": "^1.1.3",
    "quick.db": "^6.3.2",
    "weather-js": "^2.0.0",
    "snekfetch": "^4.0.4"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node bot.js"
  },
  "engines": {
    "node": "8.x"
  },
  "author": "DarkenLight Mage",
  "license": "Apache-2.0",
  "devDependencies": {
    "jshint": "^2.9.5"
  }
}

I have this in the file: module.exports = client => {, but if you see above, I require it as you said.

then it should work?

Nop. Still doesn’t work. Maybe it is a bug?

Can you give anyone access to your code. I’m sure it’s something that we just can’t see from the forum. If not, that’s totally fine, we’ll just have to try our best.

How are you calling the file?

I’ll just paste the entire dashboard.js file here. I think it’s easier. (Btw, this is not something I’ve done. [And the huge comments aren’t mine.])

/*
DASHBOARD EXAMPLE

This is a very simple dashboard example, but even in its simple state, there are still a
lot of moving parts working together to make this a reality. I shall attempt to explain
those parts in as much details as possible, but be aware: there's still a lot of complexity
and you shouldn't expect to really understand all of it instantly.

Pay attention, be aware of the details, and read the comments.

Note that this *could* be split into multiple files, but for the purpose of this
example, putting it in one file is a little simpler. Just *a little*.
*/

// quick.db
const db = require('quick.db')

// Native Node Imports
const url = require("url");
const path = require("path");
const fs = require("fs");

// Used for Permission Resolving...
const Discord = require("discord.js");

// Express Session
const express = require("express");
const app = express();

// Express Plugins
// Specifically, passport helps with oauth2 in general.
// passport-discord is a plugin for passport that handles Discord's specific implementation.
const passport = require("passport");
const session = require("express-session");
const Strategy = require("passport-discord").Strategy;

// Helmet is a security plugin
//const helmet = require('helmet');

// Used to parse Markdown from things like ExtendedHelp
const md = require("marked");

// For logging
const morgan = require("morgan");

// For stats
const moment = require("moment");
require("moment-duration-format");

module.exports = client => {
  if (client.config.dashboard.enabled !== "true")
    return client.log("log", "Dashboard disabled", "INFO");
  // It's easier to deal with complex paths.
  // This resolves to: yourbotdir/dashboard/
  const dataDir = path.resolve(`${process.cwd()}${path.sep}dashboard`);

  // This resolves to: yourbotdir/dashboard/templates/
  // which is the folder that stores all the internal template files.
  const templateDir = path.resolve(`${dataDir}${path.sep}templates`);

  app.set("trust proxy", 5); // Proxy support
  // The public data directory, which is accessible from the *browser*.
  // It contains all css, client javascript, and images needed for the site.
  app.use(
    "/public",
    express.static(path.resolve(`${dataDir}${path.sep}public`), {
      maxAge: "10d"
    })
  );
  app.use(morgan("combined")); // Logger

  // uhhhh check what these do.
  passport.serializeUser((user, done) => {
    done(null, user);
  });
  passport.deserializeUser((obj, done) => {
    done(null, obj);
  });

  /*
	This defines the **Passport** oauth2 data. A few things are necessary here.

	clientID = Your bot's client ID, at the top of your app page. Please note,
		older bots have BOTH a client ID and a Bot ID. Use the Client one.
	clientSecret: The secret code at the top of the app page that you have to
		click to reveal. Yes that one we told you you'd never use.
	callbackURL: The URL that will be called after the login. This URL must be
		available from your PC for now, but must be available publically if you're
		ever to use this dashboard in an actual bot.
	scope: The data scopes we need for data. identify and guilds are sufficient
		for most purposes. You might have to add more if you want access to more
		stuff from the user. See: https://discordapp.com/developers/docs/topics/oauth2

	See config.js.example to set these up.
	*/

  var protocol;

  if (client.config.dashboard.secure === "true") {
    client.protocol = "https://";
  } else {
    client.protocol = "http://";
  }

  protocol = client.protocol;

  client.callbackURL = `${protocol}${client.config.dashboard.domain}/callback`;
  client.log("log", `Callback URL: ${client.callbackURL}`, "INFO");
  passport.use(
    new Strategy(
      {
        clientID: client.appInfo.id,
        clientSecret: client.config.dashboard.oauthSecret,
        callbackURL: client.callbackURL,
        scope: ["identify", "guilds"]
      },
      (accessToken, refreshToken, profile, done) => {
        process.nextTick(() => done(null, profile));
      }
    )
  );

  // Session data, used for temporary storage of your visitor's session information.
  // the `secret` is in fact a 'salt' for the data, and should not be shared publicly.
  app.use(
    session({
      secret: client.config.dashboard.sessionSecret,
      resave: false,
      saveUninitialized: false
    })
  );

  // Initializes passport and session.
  app.use(passport.initialize());
  app.use(passport.session());

  // The domain name used in various endpoints to link between pages.
  app.locals.domain = client.config.dashboard.domain;

  // The EJS templating engine gives us more power
  app.engine("html", require("ejs").renderFile);
  app.set("view engine", "html");

  // body-parser reads incoming JSON or FORM data and simplifies their
  // use in code.
  var bodyParser = require("body-parser");
  app.use(bodyParser.json()); // to support JSON-encoded bodies
  app.use(
    bodyParser.urlencoded({
      // to support URL-encoded bodies
      extended: true
    })
  );

  /*
	Authentication Checks. checkAuth verifies regular authentication,
	whereas checkAdmin verifies the bot owner. Those are used in url
	endpoints to give specific permissions.
	*/
  function checkAuth(req, res, next) {
    if (req.isAuthenticated()) return next();
    req.session.backURL = req.url;
    res.redirect("/login");
  }

  function cAuth(req, res) {
    if (req.isAuthenticated()) return;
    req.session.backURL = req.url;
    res.redirect("/login");
  }

  function checkAdmin(req, res, next) {
    if (req.isAuthenticated() && req.user.id === client.config.ownerID || req.isAuthenticated() && req.user.id === client.config.subownerID)
      return next();
    req.session.backURL = req.originalURL;
    res.redirect("/");
  }

  var privacyMD = "";
  fs.readFile(
    `${process.cwd()}${path.sep}dashboard${path.sep}public${
      path.sep
    }PRIVACY.md`,
    function(err, data) {
      if (err) {
        console.log(err);
        privacyMD = "Error";
        return;
      }
      privacyMD = data
        .toString()
        .replace(/\{\{botName\}\}/g, client.user.username)
        .replace(
          /\{\{email\}\}/g,
          client.config.dashboard.legalTemplates.contactEmail
        );
      if (client.config.dashboard.secure !== "true") {
        privacyMD = privacyMD.replace(
          "Sensitive and private data exchange between the Site and its Users happens over a SSL secured communication channel and is encrypted and protected with digital signatures.",
          ""
        );
      }
    }
  );

  var termsMD = "";
  fs.readFile(
    `${process.cwd()}${path.sep}dashboard${path.sep}public${path.sep}TERMS.md`,
    function(err, data) {
      if (err) {
        console.log(err);
        privacyMD = "Error";
        return;
      }
      termsMD = data
        .toString()
        .replace(/\{\{botName\}\}/g, client.user.username)
        .replace(
          /\{\{email\}\}/g,
          client.config.dashboard.legalTemplates.contactEmail
        );
    }
  );

  // Index page. If the user is authenticated, it shows their info
  // at the top right of the screen.
  app.get("/", (req, res) => {
    if (req.isAuthenticated()) {
      res.render(path.resolve(`${templateDir}${path.sep}index.ejs`), {
        bot: client,
        auth: true,
        user: req.user
      });
    } else {
      res.render(path.resolve(`${templateDir}${path.sep}index.ejs`), {
        bot: client,
        auth: false,
        user: null
      });
    }
  });

  app.get("/stats", (req, res) => {
    if (client.config.dashboard.protectStats === "true") {
      cAuth(req, res);
    }
    const duration = moment
      .duration(client.uptime)
      .format(" D [days], H [hrs], m [mins], s [secs]");
    //const members = client.guilds.reduce((p, c) => p + c.memberCount, 0);
    const members = `${client.users.filter(u => u.id !== "1").size} (${
      client.users.filter(u => u.id !== "1").filter(u => u.bot).size
    } bots)`;
    const textChannels = client.channels.filter(c => c.type === "text").size;
    const voiceChannels = client.channels.filter(c => c.type === "voice").size;
    const guilds = client.guilds.size;
    res.render(path.resolve(`${templateDir}${path.sep}stats.ejs`), {
      bot: client,
      auth: req.isAuthenticated() ? true : false,
      user: req.isAuthenticated() ? req.user : null,
      stats: {
        servers: guilds,
        members: members,
        text: textChannels,
        voice: voiceChannels,
        uptime: duration,
        commands: client.commandsNumber,
        memoryUsage: (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2),
        dVersion: Discord.version,
        nVersion: process.version,
        bVersion: client.version
      }
    });
  });

  app.get("/legal", function(req, res) {
    md.setOptions({
      renderer: new md.Renderer(),
      gfm: true,
      tables: true,
      breaks: false,
      pedantic: false,
      sanitize: false,
      smartLists: true,
      smartypants: false
    });

    /*var showdown	= require('showdown');
		var	converter = new showdown.Converter(),
			textPr			= privacyMD,
			htmlPr			= converter.makeHtml(textPr),
			textTe			= termsMD,
			htmlTe			= converter.makeHtml(textTe);
		res.render(path.resolve(`${templateDir}${path.sep}legal.ejs`), {
			bot: client,
			auth: req.isAuthenticated() ? true : false,
			user: req.isAuthenticated() ? req.user : null,
			privacy: htmlPr.replace(/\\'/g, `'`),
			terms: htmlTe.replace(/\\'/g, `'`),
			edited: client.config.dashboard.legalTemplates.lastEdited
		});*/

    res.render(path.resolve(`${templateDir}${path.sep}legal.ejs`), {
      bot: client,
      auth: req.isAuthenticated() ? true : false,
      user: req.isAuthenticated() ? req.user : null,
      privacy: md(privacyMD),
      terms: md(termsMD),
      edited: client.config.dashboard.legalTemplates.lastEdited
    });
  });

  // The login page saves the page the person was on in the session,
  // then throws the user to the Discord OAuth2 login page.
  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) {
        res.redirect(req.session.backURL);
        req.session.backURL = null;
      } else {
        res.redirect("/");
      }
    }
  );

  app.get("/admin", checkAdmin, (req, res) => {
    res.render(path.resolve(`${templateDir}${path.sep}admin.ejs`), {
      bot: client,
      user: req.user,
      auth: true
    });
  });

  app.get("/dashboard", checkAuth, (req, res) => {
    const perms = Discord.EvaluatedPermissions;
    res.render(path.resolve(`${templateDir}${path.sep}dashboard.ejs`), {
      perms: perms,
      bot: client,
      user: req.user,
      auth: true
    });
  });

  app.get("/add/:guildID", checkAuth, (req, res) => {
    req.session.backURL = "/dashboard";
    var invitePerm = client.config.dashboard.invitePerm;
    var inviteURL = `https://discordapp.com/oauth2/authorize?client_id=${
      client.appInfo.id
    }&scope=bot&guild_id=${
      req.params.guildID
    }&response_type=code&redirect_uri=${encodeURIComponent(
      `${client.callbackURL}`
    )}&permissions=${invitePerm}`;
    if (client.guilds.has(req.params.guildID)) {
      res.send(
        '<p>The bot is already there... <script>setTimeout(function () { window.location="/dashboard"; }, 1000);</script><noscript><meta http-equiv="refresh" content="1; url=/dashboard" /></noscript>'
      );
    } else {
      res.redirect(inviteURL);
    }
  });

  app.post("/manage/:guildID", checkAuth, (req, res) => {
    const guild = client.guilds.get(req.params.guildID);
    if (!guild) return res.status(404);
    const isManaged =
      guild && !!guild.member(req.user.id)
        ? guild.member(req.user.id).permissions.has("MANAGE_GUILD")
        : false;
    if (req.user.id === client.config.ownerID || req.user.id === client.config.subownerID) {
      console.log(`Admin bypass for managing server: ${req.params.guildID}`);
    } else if (!isManaged) {
      res.redirect("/");
    }
    const settings = client.settings.get(guild.id);
    for (const key in settings) {
      var value = req.body[key];
      //console.log(typeof value);
      //console.log(value);
      /*if (value.length > 1) {
				for (var i = 0; i < value.length; i++) {
					console.log(value[i]);
					value[i] = value[i].replace(',', '');
					console.log(value[i]);
				}
			} else {*/
      if (value.indexOf(",") > -1) {
        settings[key] = value.split(",");
        //console.log('S: ' + settings[key]);
        //console.log(typeof settings[key]);
        //console.log('Split');
        //console.log(typeof value);
        //console.log(value);
      } else if (key === "inviteWhitelist") {
        var iWArray = [];
        value = value.replace(/\s/g, "");
        value.indexOf(",") > -1
          ? (iWArray = value.split(","))
          : iWArray.push(value);
        settings[key] = iWArray;
      }
      if (key === "swearWords") {
        var sWArray = [];
        value = value.replace(/\s/g, "");
        value.indexOf(",") > -1
          ? (sWArray = value.split(","))
          : sWArray.push(value);
        settings[key] = sWArray;
      } else {
        settings[key] = value;
        //console.log(typeof value);
        //console.log(value);
      }
      //settings[key] = req.body[key];
    }
    client.settings.set(guild.id, settings);
    res.redirect(`/manage/${req.params.guildID}`);
  });

  app.get("/manage/:guildID", checkAuth, (req, res) => {
    const guild = client.guilds.get(req.params.guildID);
    if (!guild) return res.status(404);
    const isManaged =
      guild && !!guild.member(req.user.id)
        ? guild.member(req.user.id).permissions.has("MANAGE_GUILD")
        : false;
    if (req.user.id === client.config.ownerID || req.user.id === client.config.subownerID) {
      console.log(`Admin bypass for managing server: ${req.params.guildID}`);
    } else if (!isManaged) {
      res.redirect("/dashboard");
    }
    res.render(path.resolve(`${templateDir}${path.sep}manage.ejs`), {
      bot: client,
      guild: guild,
      user: req.user,
      auth: true
    });
  });

  app.get("/leave/:guildID", checkAuth, async (req, res) => {
    const guild = client.guilds.get(req.params.guildID);
    if (!guild) return res.status(404);
    const isManaged =
      guild && !!guild.member(req.user.id)
        ? guild.member(req.user.id).permissions.has("MANAGE_GUILD")
        : false;
    if (req.user.id === client.config.ownerID || req.user.id === client.config.subownerID) {
      console.log(`Admin bypass for managing server: ${req.params.guildID}`);
    } else if (!isManaged) {
      res.redirect("/dashboard");
    }
    await guild.leave();
    if (req.user.id === client.config.ownerID || req.user.id === client.config.subownerID) {
      return res.redirect("/admin");
    }
    res.redirect("/dashboard");
  });

  app.get("/reset/:guildID", checkAuth, async (req, res) => {
    const guild = client.guilds.get(req.params.guildID);
    if (!guild) return res.status(404);
    const isManaged =
      guild && !!guild.member(req.user.id)
        ? guild.member(req.user.id).permissions.has("MANAGE_GUILD")
        : false;
    if (req.user.id === client.config.ownerID || req.user.id === client.config.subownerID) {
      console.log(`Admin bypass for managing server: ${req.params.guildID}`);
    } else if (!isManaged) {
      res.redirect("/dashboard");
    }
    client.settings.set(guild.id, client.config.defaultSettings);
    res.redirect(`/manage/${req.params.guildID}`);
  });

  app.get("/commands", (req, res) => {
    if (req.isAuthenticated()) {
      res.render(path.resolve(`${templateDir}${path.sep}commands.ejs`), {
        bot: client,
        auth: true,
        user: req.user,
        md: md
      });
    } else {
      res.render(path.resolve(`${templateDir}${path.sep}commands.ejs`), {
        bot: client,
        auth: false,
        user: null,
        md: md
      });
    }
  });

  app.get("/logout", function(req, res) {
    req.logout();
    res.redirect("/");
  });

  app.get("*", function(req, res) {
    // Catch-all 404
    res.send(
      '<p>404 File Not Found. Please wait...<p> <script>setTimeout(function () { window.location = "/"; }, 1000);</script><noscript><meta http-equiv="refresh" content="1; url=/" /></noscript>'
    );
  });
  
  /*app.get("/api/:action", async (req, res) => {
  let apicodes = await db.fetch(`apicodes`)
  console.log('1')
  let action = req.params.action
  if (apicodes) {
    console.log('2')
	if (apicodes.keys.includes(req.query.key)) {
	  if (apicodes.secrets.includes(req.query.secret)) {
	  if (action) {
		if (action === 'check') {
			let check = await db.fetch(`gban_${req.params.userid}`)
			if (check) {
				res.send(check)
			} else {
				res.send('Not Banned')
			}
		} else {
			if (action === 'ban') {
				let user = req.query.userid,
					reason = req.query.reason,
					evidence = req.query.evidence,
					moderator = req.query.moderator,
					requester = req.query.botid;
				let request = {type: 'ban', userID: user, reason: reason, evidence: evidence, moderator: moderator, botid: requester, status: 'Not checked'}
				await db.set(`banrequests_${requester}`)
			} else {
				if (action === 'unban') {
					let user = req.query.userid,
						reason = req.query.reason,
						moderator = req.query.moderator,
						requester = req.query.botid;
					let request = {type: 'unban', userID: user, reason: reason, moderator: moderator, botid: requester, status: 'Not checked'}
					await db.set(`banrequests_${requester}`)
				} else {
					if (action === 'editban') {
						if (req.query.reason) {
							let user = req.query.userid,
								reason = req.query.reason,
								moderator = req.query.moderator,
								requester = req.query.botid;
							let request = {type: 'editban', userID: user, reason: reason, moderator: moderator, botid: requester, status: 'Not checked'}
							await db.set(`banrequests_${requester}`)
						} else {
							if (req.query.evidence) {
								let user = req.query.userid,
									evidence = req.query.evidence,
									moderator = req.query.moderator,
									requester = req.query.botid;
								let request = {type: 'editban', userID: user, evidence: evidence, moderator: moderator, botid: requester, status: 'Not checked'}
								await db.set(`banrequests_${requester}`)
							}
						}
					} else {
						if (action === 'requests') {
							let requester = req.query.botid
							let requests = await db.fetch(`banrequests_${requester}`)
							if (requests) {
								res.send(requests)
								} else {
									res.send('No requests.')
							}
						} else {
							if (action === 'checkcon') {
								res.status(200).send('OK.')
							}
						}
					}
				}
			}
		}
	  } else {
      console.log('2')
      res.send('Invalid API call method.')}//.status(401)
	 } else res.send('Invalid API auth secret.')//.status(401)
	} else res.send('Invalid API auth key.')//.status(401)
 } else res.send('API code check broken')//.status(401)
  });*/
  console.log('a')
  
  const getAPICodes = async () => await db.fetch(`apicodes`);
  const getBannedStatus = async id => await db.fetch(`gban_${id}`);
  const banRequest = async (req, type) => {
  const { userid: userId } = req.params;
  const { reason, evidence, moderator, botid: requester } = req.query;
  const request = {
    type: type || "ban",
    userID: userId,
    reason: reason,
    evidence: evidence,
    moderator: moderator,
    botid: requester,
    status: "Not checked"
  };
  return await db.set(`banrequests_${requester}`, request);
};

const actionHandler = async (req, res) => {
  console.log('1')
  const apiCodes = await getAPICodes();
  const { keys: apiCodesKeys, secrets: apiCodesSecrets } = apiCodes;
  const { action, userid: userId } = req.params;
  const { key, secret } = req.query;
  const passingState =
    apiCodesKeys.includes(key) && apiCodesSecrets.includes(secret);

  if (!action || !apiCodes || !passingState) return res.status(401).json({
    message: "Unauthorized",
    code: 401
  })

  switch (action) {
    case "check": {
      const check = getBannedStatus(userId);

      if (check) {
        res.send(check);
      } else {
        res.send("Not Banned");
      }
    }

    case "ban": {
      res.json(banRequest(req, "ban"));
    }

    case "unban": {
      res.json(banRequest(req, "unban"));
    }

    case "editban": {
      res.json(banRequest(req, "editban"));
    }

    case "requests": {
      res.json(await db.get(`banrequests_${req.paramd.botid}`));
    }

    case "checkon": {
      res.sendStatus(200);
    }
  }
};

app.get("/api/:action", async (req, res) => await actionHandler(req, res));



  client.site = app
    .listen(client.config.dashboard.port, function() {
      client.log(
        "log",
        `Dashboard running on port ${client.config.dashboard.port}`,
        "INFO"
      );
    })
    .on("error", err => {
      client.log("ERROR", `Error with starting dashboard: ${err.code}`);
      return process.exit(0);
    });
};

I call the dashboard.js in the ready event with: require('../modules/dashboard')(client);

Try

const file = require(file).client()

But then why the other pages work, but not the ones I add? I don’t think the problem is with how the file is called. :confused:

You have app.get('*'), so any middleware after that line will be thrown out. Put your code above it, or put that line at the end of the code

PS. comments are not that huge, half of the serious code (in a perfect scenario) should be just comments

2 Likes

Still gave me the 404 error. :confused:

In case you want to see the 404 handler, here it is:

app.get("*", function(req, res) {
    // Catch-all 404
    res.send(
      '<p>404 File Not Found. Please wait...<p> <script>setTimeout(function () { window.location = "/"; }, 1000);</script><noscript><meta http-equiv="refresh" content="1; url=/" /></noscript>'
    );
  });

I’ve seen it already, can you share the project name? And, what path are you requesting? Maybe there should be four-o-four because you’re going for a wrong path

My project’s name is global-protector. And wdym by path?

By path I mean the URL you’re going

But I can access these :action, what’s wrong with yours?

Oh. It works now. Strange. I used all these alot of times:

https://global-protector.glitch.me/api/ban
https://global-protector.glitch.me/api/unban
https://global-protector.glitch.me/api/editban
https://global-protector.glitch.me/api/requests
https://global-protector.glitch.me/api/check

And they didn’t work. But it now works. Thank you @jarvis394.

@jarvis394 by the way, can I still add an html page to https://global-protector.glitch.me/api?

Yes, why not. Just add the code before the '*' wildcard

Uhmmm… Seems like I have a little problem here… The website just gets stuck in an infinite loop when I try to access the /api page.

Here’s the router (it’s before the api/:action):

app.get("/api", checkAuth, async (req, res) => {
  let apiallow = await db.fetch('apiallow')
	if (apiallow.includes(req.user.id)) {
		res.render(path.resolve(`${templateDir}${path.sep}api.ejs`), {
		bot: client,
		user: req.user,
		auth: true
	 });
	}
  });

dashboard/templates/api.ejs:

<%
	const db = require('quick.db')
	let keys = await db.fetch(`apikeys_${user.id}`)
%>

<%- include('blocks/header', {bot:bot, user: user, auth: auth}) %>
<div class="jumbotron">
    <div class="col-sm-8 mx-auto">
      <div class="row">
				<div class="col">
          <i class="fa fa-user fa-fw" aria-hidden="true"></i> In this page, you can create and manage your API keys.
       </div>
		<div class="col">
          <i class="fa fa-user fa-fw" aria-hidden="true"></i> Total API keys: <%= `${keys.total}` %>
        </div>
      </div>
    </div>
    <div class="col-sm-8 mx-auto" style="margin-top: 15px;">
      <p>
        <a class="btn btn-success" data-toggle="modal" data-target="#ApiAuthnewKeyModal" role="button">New key <i class="fas fa-plus" aria-hidden="true"></i></a>
      </p>
    </div>
  </div>

<h1 class="display-4">API Auth Keys</h1>

<form method="post">
  <% for (const key in keys) { %>
  <div class="card">
            <h3 class="card-header">**************<%= key.id.slice(key.length - 4) %></h3>
              <div class="card-block" style="margin: 7px">
                <h6 class="card-subtitle text-muted">Enabled: <%= key.enabled %><br /><a href="#" data-toggle="modal" data-target="#<%= `${key.id}` %>Modal">Detailed info</a></h6>
              </div>
          </div>
		  <div id="<%= `${key.id}` %>Modal" class="modal fade" role="dialog">
            <div class="modal-dialog">
              <div class="modal-content">
                <div class="modal-header btn-info disabled">
                  <h4 class="modal-title">Auth ID #<%= key.id %></h4>
                  <button type="button" class="close" data-dismiss="modal">&times;</button>
                </div>
                <div class="modal-body">
                  <p><span style="font-weight: bold;">Key:</span> <%= key.key %></p>
                    <p><span style="font-weight: bold;">Secret:</span> <%= key.secret %></p>
                    <p><span style="font-weight: bold;">Enabled:</span> <%= key.enabled %></p>
                    <p><span style="font-weight: bold;">Atributed to bot id:</span> <%= key.botid %></p>
					<%if (key.enabled === 'true') {%>
					<%let authid = key.id%>
					<p>
						<a class="btn btn-success" data-toggle="modal" data-target="#ApiAuthEnableModal" role="button">Enable <i class="fas fa-plus" aria-hidden="true"></i></a>
					</p>	
					<% } else { %>
					<%let authid = key.id%>
					<p>
						<a class="btn btn-danger" data-toggle="modal" data-target="#ApiAuthDisableModal" role="button">Disable <i class="fas fa-plus" aria-hidden="true"></i></a>
					</p>
					<% } %>
					<p>
						<a class="fas fa-trash-alt" data-toggle="modal" data-target="#ApiAuthDeleteModal" role="button">Enable <i class="fas fa-plus" aria-hidden="true"></i></a>
					</p>
                  </div>
                <div class="modal-footer"><button type="button" class="btn btn-outline-danger" data-dismiss="modal">Close</button></div>
              </div>
            </div>
          </div>
  <% } %>
</form>




<!-- Manage Page Modals -->
<div class="modal fade" id="ApiAuthDeleteModal" tabindex="-1" role="dialog" aria-labelledby="ApiAuthDeleteModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="ApiAuthDeleteModalLabel">Delete auth?</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>
          Are you sure you want to delete the API auth <%= authid%>?
        </p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
        <a class="btn btn-primary" href="/deletekey/<%= authid %>" role="button">Leave</a>
      </div>
    </div>
  </div>
</div>

<!-- Manage Page Modals -->
<script>
async function enable(authid) {
	let fetch = await db.fetch(`apikeys_${user.id}`)
	for (var i in fetch) {
		if (fetch[i].id === authid) {
			await db.set(`apikeys_${user.id}[i]`, 'true', {target: '.enabled'})
		}
	}
}
</script>
<div class="modal fade" id="ApiAuthEnableModal" tabindex="-1" role="dialog" aria-labelledby="ApiAuthEnableModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="ApiAuthEnableModalLabel">Enable auth?</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>
          Are you sure you want to enable the API auth <%= authid%>?
        </p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-primary" onclick=`enable(authid)`>Enable</a>
      </div>
    </div>
  </div>
</div>

<!-- Manage Page Modals -->
<script>
async function disable(authid) {
	let fetch = await db.fetch(`apikeys_${user.id}`)
	for (var i in fetch) {
		if (fetch[i].id === authid) {
			await db.set(`apikeys_${user.id}[i]`, 'false', {target: '.enabled'})
		}
	}
}
</script>
<div class="modal fade" id="ApiAuthDisableModal" tabindex="-1" role="dialog" aria-labelledby="ApiAuthDisableModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="ApiAuthDisableModalLabel">Disable auth?</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>
          Are you sure you want to disable the API auth <%= authid%>?
        </p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-primary" onclick=`disable(authid)`>Disable</a>
      </div>
    </div>
  </div>
</div>

<!-- Manage Page Modals -->
<div class="modal fade" id="ApiAuthnewKeyModal" tabindex="-1" role="dialog" aria-labelledby="ApiAuthnewKeyModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="ApiAuthnewKeyModalLabel">Create new API Auth Key?</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>
          Are you sure you want to create a new API Auth key?
        </p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
        <a class="btn btn-primary" href="/newkey" role="button">Create</a>
      </div>
    </div>
  </div>
</div>

<% include ./blocks/footer %>

apiallow has my discord id and my friend’s discord id. Am I doing something wrong?

Your trying to access Node.js form the client.

You are driving me crazy with the horrible indents.

It has server side rendering using the ejs engine, hopefully turned on earlier than this route.

There’s no action to take if this doesn’t equate to true, if you log an error message and send some response it’d be easier to work out what’s happening.

1 Like

The indents are horrible because I’m new to ejs and I need to copy paste alot of ejs code to make the pages work (unsuccesfully.)

And I figured out the problem, but now I have a problem that “keys” is not defined. How to do it?