Skip to content
This repository has been archived by the owner on Dec 13, 2021. It is now read-only.

Commit

Permalink
Merge pull request #4 from MattIPv4/feat/db
Browse files Browse the repository at this point in the history
Removed Files
  • Loading branch information
MattIPv4 committed Oct 6, 2019
2 parents a6af7ed + e47a86f commit 92fce0f
Show file tree
Hide file tree
Showing 18 changed files with 668 additions and 441 deletions.
2 changes: 1 addition & 1 deletion src/Jobs/IconUpdater.js
Expand Up @@ -9,7 +9,7 @@ class IconUpdater extends BaseJob {
}

execute() {
this.db.run('SELECT * FROM lists WHERE display = ? AND defunct = ?', [1, 0]).then((lists) => {
this.db.select().from('lists').where({ display: true, defunct: false }).then((lists) => {
for (let i = 0; i < lists.length; i++) {
updateIcon(this.client, this.db, lists[i]).then((m) => {
console.log(m)
Expand Down
363 changes: 232 additions & 131 deletions src/Routes/API.js

Large diffs are not rendered by default.

14 changes: 10 additions & 4 deletions src/Routes/Index.js
Expand Up @@ -2,6 +2,7 @@ const fs = require('fs');
const { join } = require('path');
const BaseRoute = require('../Structure/BaseRoute');
const Renderer = require('../Structure/Markdown');
const shuffle = require('../Util/shuffle');

class IndexRoute extends BaseRoute {
constructor(client, db) {
Expand All @@ -15,23 +16,28 @@ class IndexRoute extends BaseRoute {

routes() {
this.router.get('/', (req, res) => {
this.db.run('SELECT * FROM lists WHERE discord_only = ? AND display = ? AND defunct = ? ORDER BY RAND() LIMIT 2', [1, 1, 0]).then((lists) => {
this.db.select().from('lists').where({
discord_only: true,
display: true,
defunct: false
}).then(lists => {
lists = shuffle(lists).slice(0, 2);
res.render('home', { lists });
}).catch(() => {
res.status(500).render('error', {title: 'Database Error'});
res.status(500).render('error', { title: 'Database Error' });
})
});

this.router.get('/about', (req, res) => {
this.db.run('SELECT * FROM about ORDER BY position ASC').then((data) => {
this.db.select().from('about').orderBy('position', 'asc').then((data) => {
const sections = data.map(section => {
section.title = this.renderer.variables(section.title);
section.content = this.renderer.render(section.content);
return section;
});
res.render('about', { title: 'About', sections });
}).catch((e) => {
res.status(500).render('error', {title: 'Database Error'});
res.status(500).render('error', { title: 'Database Error' });
})
});

Expand Down
277 changes: 182 additions & 95 deletions src/Routes/Lists.js

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions src/Structure/Cache.js
Expand Up @@ -5,7 +5,7 @@ class Cache {

async get(path) {
try {
return (await this.db.run('SELECT * FROM cache WHERE route = ?', [path]))[0];
return (await this.db.select().from('cache').where({ route: path }))[0];
} catch {
return null;
}
Expand All @@ -20,7 +20,11 @@ class Cache {
*/
async add(route, expiry, data) {
try {
return await this.db.run('INSERT INTO cache (route, expiry, data) VALUES (?, ?, ?)', [route, (Date.now() + expiry) / 1000, JSON.stringify(data)]);
return await this.db('cache').insert({
route,
expiry: (Date.now() + expiry) / 1000,
data: JSON.stringify(data)
});
} catch (e) {
return null;
}
Expand All @@ -32,7 +36,7 @@ class Cache {

async deleteExpired() {
try {
return await this.db.run('DELETE FROM cache WHERE expiry < ?', [new Date().getSeconds()])
return await this.db('cache').where('expiry', '<', new Date().getSeconds()).del();
} catch {
return null;
}
Expand Down
45 changes: 0 additions & 45 deletions src/Structure/Database.js

This file was deleted.

26 changes: 23 additions & 3 deletions src/Structure/RateLimiter.js
Expand Up @@ -7,36 +7,56 @@ class RateLimiter {
}

checkRatelimit(requestLimit = 1, timeLimit = 1, bot = '') {
// Remember: Ratelimiting uses milliseconds internally, but timeLimit is in seconds
return async (req, res, next) => {
await this.db('ratelimit')
.where('expiry', '<', Date.now())
.del();

// Test suite ratelimit bypass
const ratelimitBypass = req.get('X-Ratelimit-Bypass');
if (ratelimitBypass === secret) return next();

// Ratelimit as normal
if (req.body.bot_id && !bot) bot = req.body.bot_id;
if (typeof bot !== "string" || !isSnowflake(bot)) bot = '';
try {
await this.db.run('DELETE FROM ratelimit WHERE ip = ? AND bot_id = ? AND route = ? AND expiry < ?', [req.ip, bot, req.originalUrl, Date.now()]);
const recent = await this.db.run('SELECT * FROM ratelimit WHERE ip = ? AND bot_id = ? AND route = ? ORDER BY datetime DESC', [req.ip, bot, req.originalUrl]);
const recent = await this.db.select().from('ratelimit').where({
ip: req.ip,
bot_id: bot,
route: req.originalUrl
}).orderBy('datetime', 'desc');

if (recent && recent.length >= requestLimit) {
const expiry = recent[0].expiry;
const retry = Math.round((expiry - Date.now()) / 1000);
const reset = Math.round(expiry / 1000);

res.set('Retry-After', retry);
res.set('X-Rate-Limit-Reset', reset);
res.set('X-Rate-Limit-IP', req.ip);
res.set('X-Rate-Limit-Route', req.originalUrl);
res.set('X-Rate-Limit-Bot-ID', bot);

return res.status(429).json({
error: true,
status: 429,
retry_after: retry,
ratelimit_reset: reset,
timestamp: Math.round(Date.now() / 1000),
ratelimit_ip: req.ip,
ratelimit_route: req.originalUrl,
ratelimit_bot_id: bot
});
}
await this.db.run('INSERT INTO ratelimit (ip, bot_id, route, datetime, expiry) VALUES (?, ?, ?, ?, ?)', [req.ip, bot, req.originalUrl, Date.now(), Date.now() + timeLimit * 1000]);

await this.db('ratelimit').insert({
ip: req.ip,
bot_id: bot,
route: req.originalUrl,
datetime: Date.now(),
expiry: Date.now() + timeLimit * 1000,
});
next();
} catch (_) {
res.status(500).json({ error: true, status: 500, message: 'An unexpected error occurred' });
Expand Down
2 changes: 1 addition & 1 deletion src/Util/getListFeature.js
@@ -1,6 +1,6 @@
module.exports = async (db, id) => {
try {
const feature = await db.run('SELECT * FROM features WHERE id = ?', [id]);
const feature = await db.select().from('features').where({ id });
if (!feature) return null;
return feature[0];
} catch (e) {
Expand Down
25 changes: 25 additions & 0 deletions src/Util/getListFeatures.js
@@ -0,0 +1,25 @@
module.exports = async (db, id) => {
const allFeatures = await db.select().from('features');
const listFeatures = await db.select().from('feature_map').where({ list: id });
const map = listFeatures.reduce((obj, item) => {
obj[item.feature] = item.value;
return obj
}, {});
return allFeatures.map(feature => {
return {
name: feature.name,
id: feature.id,
display: feature.display,
type: feature.type,
value: feature.id in map ? map[feature.id] : 0
}
}).sort((a, b) => {
if (a.value === b.value) {
if (a.display === b.display) {
return a.name > b.name ? 1 : -1;
}
return b.display - a.display
}
return b.value - a.value
});
};
2 changes: 1 addition & 1 deletion src/Util/handleError.js
@@ -1,6 +1,6 @@
module.exports = (db, verb, route, error, api = false) => {
try {
return db.run('INSERT INTO errors (verb, route, error, datetime) VALUES (?, ?, ?, ?)', [verb, route, error, Date.now() / 1000]);
return db('errors').insert({ verb, route, error, datetime: Date.now() / 1000 });
} catch (e) {
console.error('[Handle Error] Failed to log error. Error: %s\n Error to log:', e, error);
return null;
Expand Down
20 changes: 20 additions & 0 deletions src/Util/shuffle.js
@@ -0,0 +1,20 @@
// Credit: https://github.com/Daplie/knuth-shuffle/blob/master/index.js
module.exports = array => {
let currentIndex = array.length;
let temporaryValue, randomIndex;

// While there remain elements to shuffle...
while (0 !== currentIndex) {

// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;

// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}

return array;
};
2 changes: 1 addition & 1 deletion src/Util/updateIcon.js
Expand Up @@ -10,7 +10,7 @@ module.exports = (client, db, list) => {
client.getInvite(code[1]).then((i) => {
const newIcon = 'https://cdn.discordapp.com/icons/' + i.guild.id + '/' + i.guild.icon + '.png';
if (list.icon === newIcon) return reject('Icon has not changed.');
db.run('UPDATE lists SET icon = ? WHERE id = ?', [newIcon, list.id]).then(() => {
db('lists').where({ id: list.id}).update({ icon: newIcon }).then(() => {
newList['icon'] = newIcon;
client.updateEditLog(list, newList).then(() => console.log(1)).catch((e) => console.error('[Discord] Failed to send to edit log', e));
resolve('Icon has been updated.');
Expand Down
10 changes: 5 additions & 5 deletions src/Util/updateListMessage.js
Expand Up @@ -5,14 +5,14 @@ module.exports = async (client, db, list, newListID) => {
let msg;
try {
let message = formatListMessage(list);
const messageid = await db.run('SELECT * FROM lists_messages WHERE list = ?', [list.id]);
if (messageid[0]) {
msg = await client.editMessage(config.discord.lists_log, messageid[0].message, message);
const messageId = await db.select('message').from('lists_messages').where({ list: list.id });
if (messageId[0]) {
msg = await client.editMessage(config.discord.lists_log, messageId[0].message, message);
} else {
msg = await client.createMessage(config.discord.lists_log, message);
}
await db.run('DELETE FROM lists_messages WHERE list = ?', [list.id]);
await db.run('INSERT INTO lists_messages (list, message) VALUES (?, ?)', [newListID, msg.id]);
await db('lists_messages').where({ list: list.id }).del();
await db('lists_messages').insert( { list: newListID, message: msg.id });
} catch (e) {
return null;
}
Expand Down
10 changes: 4 additions & 6 deletions src/main.js
@@ -1,16 +1,14 @@
const config = require('../config');
const Website = require('./Website');
const Database = require('./Structure/Database');
const db = require('../db/db');

return new Promise(async () => {
const db = new Database(config.database);
try {
await db.connect();
const knex = db();
console.log('[Database] Successfully connected to MySQL database.');
new Website({
db: db
db: knex
}).start();
} catch (e) {
console.error('[Website] Failed to start Website.', e);
}
})
});

0 comments on commit 92fce0f

Please sign in to comment.