Fix up paths; add basic About page; strip tags from input

This commit is contained in:
Robbie Antenesse 2018-12-27 15:47:06 -07:00
parent d7e77dc4dc
commit e2a265783e
6 changed files with 58 additions and 21 deletions

View File

@ -21,6 +21,7 @@
"snarkdown": "^1.2.2", "snarkdown": "^1.2.2",
"socket.io": "^2.2.0", "socket.io": "^2.2.0",
"socket.io-client": "^2.2.0", "socket.io-client": "^2.2.0",
"striptags": "^3.1.1",
"unused-filename": "^1.0.0" "unused-filename": "^1.0.0"
} }
} }

View File

@ -8,6 +8,7 @@ const bodyParser = require('body-parser');
const fileUpload = require('express-fileupload'); const fileUpload = require('express-fileupload');
const filenamify = require('filenamify'); const filenamify = require('filenamify');
const unusedFilename = require('unused-filename'); const unusedFilename = require('unused-filename');
const striptags = require('striptags');
const snarkdown = require('snarkdown'); const snarkdown = require('snarkdown');
const fecha = require('fecha'); const fecha = require('fecha');
@ -45,7 +46,7 @@ function Server () {
this.server.use('/js', express.static(path.resolve('./node_modules/socket.io-client/dist/'))); this.server.use('/js', express.static(path.resolve('./node_modules/socket.io-client/dist/')));
this.server.get('/', (req, res) => { this.server.get('/', (req, res) => {
const html = this.generateHomePage(); const html = this.generateHomePage(req);
if (html) { if (html) {
res.send(html); res.send(html);
} else { } else {
@ -54,11 +55,13 @@ function Server () {
}); });
this.server.get('/give', (req, res) => { this.server.get('/give', (req, res) => {
const body = this.fillTemplate('./templates/pages/uploadForm.html'); const resourcePath = (req.url.substr(-1) === '/' ? '../' : './');
const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', body }); const body = this.fillTemplate('./templates/pages/uploadForm.html', { resourcePath });
const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body });
res.send(html); res.send(html);
}); });
this.server.post('/give', (req, res) => { this.server.post('/give', (req, res) => {
const resourcePath = (req.url.substr(-1) === '/' ? '../' : './');
if (Object.keys(req.files).length > 0 if (Object.keys(req.files).length > 0
&& req.body.hasOwnProperty('title') && req.body.title.trim() !== '' && req.body.hasOwnProperty('title') && req.body.title.trim() !== ''
&& req.body.hasOwnProperty('summary') && req.body.summary.trim() !== '') { && req.body.hasOwnProperty('summary') && req.body.summary.trim() !== '') {
@ -76,7 +79,7 @@ function Server () {
content: messageBox, content: messageBox,
}); });
const body = this.fillTemplate('./templates/pages/uploadForm.html'); const body = this.fillTemplate('./templates/pages/uploadForm.html');
const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', body, modal }); const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, modal });
res.send(html); res.send(html);
}, (err) => { }, (err) => {
const messageBox = this.fillTemplate('./templates/elements/messageBox.html', { const messageBox = this.fillTemplate('./templates/elements/messageBox.html', {
@ -89,7 +92,7 @@ function Server () {
content: messageBox, content: messageBox,
}); });
const body = this.fillTemplate('./templates/pages/uploadForm.html'); const body = this.fillTemplate('./templates/pages/uploadForm.html');
const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', body, modal }); const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, modal });
res.send(html); res.send(html);
}); });
} else { } else {
@ -109,13 +112,23 @@ function Server () {
message: errorMessage, message: errorMessage,
}); });
const body = this.fillTemplate('./templates/pages/uploadForm.html'); const body = this.fillTemplate('./templates/pages/uploadForm.html');
const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', body, message }); const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, message });
res.send(html); res.send(html);
} }
}); });
this.server.get('/history', (req, res) => { this.server.get('/history', (req, res) => {
const html = this.generateHistoryPage(); const html = this.generateHistoryPage(req);
if (html) {
res.send(html);
} else {
res.send('Something went wrong!');
}
});
this.server.get('/about', (req, res) => {
const body = this.fillTemplate('./templates/pages/about.html');
const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'About', body });
if (html) { if (html) {
res.send(html); res.send(html);
} else { } else {
@ -173,7 +186,7 @@ Server.prototype.fillTemplate = function (file, templateVars = {}) {
return data; return data;
} }
Server.prototype.generateHomePage = function () { Server.prototype.generateHomePage = function (req) {
const files = fs.readdirSync(this.fileLocation).filter(fileName => fileName.includes('.json')); const files = fs.readdirSync(this.fileLocation).filter(fileName => fileName.includes('.json'));
const books = files.map(fileName => { const books = files.map(fileName => {
const bookData = JSON.parse(fs.readFileSync(path.resolve(this.fileLocation, fileName), 'utf8')); const bookData = JSON.parse(fs.readFileSync(path.resolve(this.fileLocation, fileName), 'utf8'));
@ -181,13 +194,13 @@ Server.prototype.generateHomePage = function () {
const id = fileName.replace('.json', ''); const id = fileName.replace('.json', '');
const confirmId = 'confirm_' + id; const confirmId = 'confirm_' + id;
const added = fecha.format(new Date(bookData.added), 'dddd MMMM Do, YYYY'); const added = fecha.format(new Date(bookData.added), 'hh:mm:ssA on dddd MMMM Do, YYYY');
const modal = this.fillTemplate('./templates/elements/modalCard.html', { const modal = this.fillTemplate('./templates/elements/modalCard.html', {
id, id,
header: '<h2 class="title">' + bookData.title + '</h2><h4 class="subtitle">' + bookData.author + '</h4>', header: '<h2 class="title">' + bookData.title + '</h2><h4 class="subtitle">' + bookData.author + '</h4>',
content: this.fillTemplate('./templates/elements/bookInfo.html', { content: this.fillTemplate('./templates/elements/bookInfo.html', {
contributor: bookData.contributor, contributor: bookData.contributor,
fileFormat: bookData.fileFormat, fileFormat: bookData.fileType,
added, added,
summary: snarkdown(bookData.summary), summary: snarkdown(bookData.summary),
}) })
@ -209,16 +222,20 @@ Server.prototype.generateHomePage = function () {
}); });
}).join(''); }).join('');
const body = '<div class="columns is-multiline">' + books + '</div>'; const body = '<div class="columns is-multiline">' + books + '</div>';
return this.fillTemplate('./templates/htmlContainer.html', { title: 'View', body }); return this.fillTemplate('./templates/htmlContainer.html', {
title: 'View',
resourcePath: (req.url.substr(-1) === '/' ? '../' : './'),
body
});
} }
Server.prototype.generateHistoryPage = function () { Server.prototype.generateHistoryPage = function (req) {
const files = fs.readdirSync(this.historyLocation).filter(fileName => fileName.includes('.json')); const files = fs.readdirSync(this.historyLocation).filter(fileName => fileName.includes('.json'));
const history = files.map(fileName => { const history = files.map(fileName => {
const bookData = JSON.parse(fs.readFileSync(path.resolve(this.historyLocation, fileName), 'utf8')); const bookData = JSON.parse(fs.readFileSync(path.resolve(this.historyLocation, fileName), 'utf8'));
const id = fileName.replace('.json', ''); const id = fileName.replace('.json', '');
const added = fecha.format(new Date(bookData.added), 'dddd MMMM Do, YYYY'); const added = fecha.format(new Date(bookData.added), 'hh:mm:ssA on dddd MMMM Do, YYYY');
const removed = fecha.format(new Date(parseInt(id)), 'dddd MMMM Do, YYYY'); const removed = fecha.format(new Date(parseInt(id)), 'hh:mm:ssA on dddd MMMM Do, YYYY');
const removedTag = '<div class="control"><div class="tags has-addons"><span class="tag">Taken</span><span class="tag is-primary">' + removed + '</span></div></div>'; const removedTag = '<div class="control"><div class="tags has-addons"><span class="tag">Taken</span><span class="tag is-primary">' + removed + '</span></div></div>';
const modal = this.fillTemplate('./templates/elements/modalCard.html', { const modal = this.fillTemplate('./templates/elements/modalCard.html', {
id, id,
@ -241,7 +258,11 @@ Server.prototype.generateHistoryPage = function () {
}); });
}).join(''); }).join('');
const body = '<div class="columns is-multiline">' + history + '</div>'; const body = '<div class="columns is-multiline">' + history + '</div>';
return this.fillTemplate('./templates/htmlContainer.html', { title: 'History', resourcePath: '../', body }); return this.fillTemplate('./templates/htmlContainer.html', {
title: 'History',
resourcePath: (req.url.substr(-1) === '/' ? '../' : './'),
body
});
} }
Server.prototype.broadcastVisitors = function () { Server.prototype.broadcastVisitors = function () {
@ -261,10 +282,10 @@ Server.prototype.addBook = function (uploadData = {}, success = () => {}, error
const bookPath = path.resolve(this.fileLocation, bookId); const bookPath = path.resolve(this.fileLocation, bookId);
const bookData = { const bookData = {
title: uploadData.title.trim(), title: striptags(uploadData.title.trim()),
author: uploadData.author.trim(), author: striptags(uploadData.author.trim()),
summary: uploadData.summary.trim(), summary: striptags(uploadData.summary.trim().replace(/\r\n/g, '\n')),
contributor: uploadData.contributor.trim(), contributor: striptags(uploadData.contributor.trim()),
added: Date.now(), added: Date.now(),
fileType: book.name.substr(book.name.lastIndexOf('.')), fileType: book.name.substr(book.name.lastIndexOf('.')),
} }

View File

@ -40,7 +40,7 @@
Give Give
</a> </a>
<a class="navbar-item" href="/history/"> <a class="navbar-item" href="/history">
History History
</a> </a>
</div> </div>

View File

@ -0,0 +1,10 @@
<div class="content">
<p>
{{siteTitle}} is a digital give a book, take a book website for e-books.
</p>
<p>
Books that can be diven and are available here are in the following formats:<br>
<code>{{allowedFormats}}</code><br>
with {{maxFileSize}} maximum file size.
</p>
</div>

View File

@ -1,4 +1,4 @@
<form action="./give" method="post" enctype="multipart/form-data"> <form action="{{resourcePath}}give" method="post" enctype="multipart/form-data">
<div class="field"> <div class="field">
<label class="label" for="title">Book Title:</label> <label class="label" for="title">Book Title:</label>
<div class="control"> <div class="control">

View File

@ -778,6 +778,11 @@ strip-outer@^1.0.0:
dependencies: dependencies:
escape-string-regexp "^1.0.2" escape-string-regexp "^1.0.2"
striptags@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.1.1.tgz#c8c3e7fdd6fb4bb3a32a3b752e5b5e3e38093ebd"
integrity sha1-yMPn/db7S7OjKjt1LltePjgJPr0=
to-array@0.1.4: to-array@0.1.4:
version "0.1.4" version "0.1.4"
resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"