diff --git a/routes/get_about.js b/routes/get_about.js index 130eda4..361e034 100644 --- a/routes/get_about.js +++ b/routes/get_about.js @@ -1,8 +1,8 @@ module.exports = function (app) { app.server.get('/about', (req, res) => { const resourcePath = (req.url.substr(-1) === '/' ? '../' : './'); - const body = app.fillTemplate('./templates/pages/about.html', { resourcePath }); - const html = app.fillTemplate('./templates/htmlContainer.html', { title: 'About', body }); + const body = app.templater.fill('./templates/pages/about.html', { resourcePath }); + const html = app.templater.fill('./templates/htmlContainer.html', { title: 'About', body }); if (html) { res.send(html); } else { diff --git a/routes/get_give.js b/routes/get_give.js index ad93bc1..4990b4a 100644 --- a/routes/get_give.js +++ b/routes/get_give.js @@ -1,10 +1,10 @@ module.exports = function (app) { app.server.get('/give', (req, res) => { const resourcePath = (req.url.substr(-1) === '/' ? '../' : './'); - let body = app.fillTemplate('./templates/pages/uploadForm.html', { resourcePath }); + let body = app.templater.fill('./templates/pages/uploadForm.html', { resourcePath }); body = app.replaceBodyWithTooManyBooksWarning(body); - const html = app.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body }); + const html = app.templater.fill('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body }); res.send(html); }); } \ No newline at end of file diff --git a/routes/get_history.js b/routes/get_history.js index a743183..b0f2534 100644 --- a/routes/get_history.js +++ b/routes/get_history.js @@ -18,10 +18,10 @@ module.exports = function (app) { const added = fecha.format(new Date(bookData.added), 'hh:mm:ssA on dddd MMMM Do, YYYY'); const removed = fecha.format(new Date(parseInt(id)), 'hh:mm:ssA on dddd MMMM Do, YYYY'); const removedTag = '
Taken' + removed + '
'; - const modal = app.fillTemplate('./templates/elements/modalCard.html', { + const modal = app.templater.fill('./templates/elements/modalCard.html', { id, header: '

' + bookData.title + '

' + bookData.author + '

', - content: app.fillTemplate('./templates/elements/bookInfo.html', { + content: app.templater.fill('./templates/elements/bookInfo.html', { contributor: bookData.contributor, fileFormat: bookData.fileType, added, @@ -30,7 +30,7 @@ module.exports = function (app) { }), footer: 'Close', }); - return app.fillTemplate('./templates/elements/book.html', { + return app.templater.fill('./templates/elements/book.html', { id, title: bookData.title, author: bookData.author, @@ -44,7 +44,7 @@ module.exports = function (app) { } const body = '

History

' + history + '
'; - const html = app.fillTemplate('./templates/htmlContainer.html', { + const html = app.templater.fill('./templates/htmlContainer.html', { title: 'History', resourcePath: (req.url.substr(-1) === '/' ? '../' : './'), body diff --git a/routes/get_home.js b/routes/get_home.js index 43bada1..3456ae3 100644 --- a/routes/get_home.js +++ b/routes/get_home.js @@ -19,25 +19,25 @@ module.exports = function (app) { const id = fileName.replace('.json', ''); const confirmId = 'confirm_' + id; const added = fecha.format(new Date(bookData.added), 'hh:mm:ssA on dddd MMMM Do, YYYY'); - const modal = app.fillTemplate('./templates/elements/modalCard.html', { + const modal = app.templater.fill('./templates/elements/modalCard.html', { id, header: '

' + bookData.title + '

' + bookData.author + '

', - content: app.fillTemplate('./templates/elements/bookInfo.html', { + content: app.templater.fill('./templates/elements/bookInfo.html', { contributor: bookData.contributor, fileFormat: bookData.fileType, added, summary: snarkdown(bookData.summary), }) - + app.fillTemplate('./templates/elements/modal.html', { + + app.templater.fill('./templates/elements/modal.html', { id: confirmId, - content: app.fillTemplate('./templates/elements/messageBox.html', { + content: app.templater.fill('./templates/elements/messageBox.html', { header: 'Download Your Book', - message: app.fillTemplate('./templates/elements/takeConfirm.html', { id }), + message: app.templater.fill('./templates/elements/takeConfirm.html', { id }), }), }), footer: 'Close Take Book', }); - return app.fillTemplate('./templates/elements/book.html', { + return app.templater.fill('./templates/elements/book.html', { id, title: bookData.title, author: bookData.author, @@ -51,7 +51,7 @@ module.exports = function (app) { } const body = '

Available Books

' + books + '
'; - const html = app.fillTemplate('./templates/htmlContainer.html', { + const html = app.templater.fill('./templates/htmlContainer.html', { title: 'View', resourcePath: (req.url.substr(-1) === '/' ? '../' : './'), body diff --git a/routes/get_tools.js b/routes/get_tools.js index 62eaa80..072d7fc 100644 --- a/routes/get_tools.js +++ b/routes/get_tools.js @@ -5,12 +5,12 @@ module.exports = function (app) { app.server.get('/tools', (req, res) => { if (req.query.pass === settings.toolsPassword) { const templateValues = {}; - let html = app.fillTemplate('./templates/pages/tools.html', templateValues); + let html = app.templater.fill('./templates/pages/tools.html', templateValues); if (req.query.do && ['resetVisitors'].includes(req.query.do)) { app.connections = 0; templateValues.resetVisitors = 'Done!'; - html = app.fillTemplate('./templates/pages/tools.html', templateValues); + html = app.templater.fill('./templates/pages/tools.html', templateValues); res.send(html); } else if (req.query.dl && ['files', 'history'].includes(req.query.dl)) { const onezip = require('onezip'); @@ -25,7 +25,7 @@ module.exports = function (app) { .on('error', (error) => { console.error(error); templateValues[dl + 'Download'] = 'Something went wrong: ' + JSON.stringify(error); - html = app.fillTemplate('./templates/pages/tools.html', templateValues); + html = app.templater.fill('./templates/pages/tools.html', templateValues); res.send(html); }) .on('end', () => { @@ -33,7 +33,7 @@ module.exports = function (app) { let backupLocation = saveLocation.replace(/\\/g, '/'); backupLocation = backupLocation.substr(backupLocation.lastIndexOf('/')); templateValues[dl + 'Download'] = 'Download (This will be removed from the server in 1 hour)'; - html = app.fillTemplate('./templates/pages/tools.html', templateValues); + html = app.templater.fill('./templates/pages/tools.html', templateValues); res.send(html); console.log('Will delete ' + saveLocation + ' in 1 hour'); setTimeout(() => { diff --git a/routes/post_give.js b/routes/post_give.js index 6563663..f3d945c 100644 --- a/routes/post_give.js +++ b/routes/post_give.js @@ -8,32 +8,32 @@ module.exports = function (app) { const { book } = req.files; const fileType = book.name.substr(book.name.lastIndexOf('.')); app.addBook({ book, title, author, summary, contributor, fileType }, () => { - const messageBox = app.fillTemplate('./templates/elements/messageBox.html', { + const messageBox = app.templater.fill('./templates/elements/messageBox.html', { style: 'is-success', header: 'Upload Successful', message: 'Thank you for your contribution!' }); - const modal = app.fillTemplate('./templates/elements/modal.html', { + const modal = app.templater.fill('./templates/elements/modal.html', { isActive: 'is-active', content: messageBox, }); - let body = app.fillTemplate('./templates/pages/uploadForm.html', { resourcePath }); + let body = app.templater.fill('./templates/pages/uploadForm.html', { resourcePath }); body = app.replaceBodyWithTooManyBooksWarning(body); - const html = app.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, modal }); + const html = app.templater.fill('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, modal }); res.send(html); }, (err) => { - const messageBox = app.fillTemplate('./templates/elements/messageBox.html', { + const messageBox = app.templater.fill('./templates/elements/messageBox.html', { style: 'is-danger', header: 'Upload Failed', message: err, }); - const modal = app.fillTemplate('./templates/elements/modal.html', { + const modal = app.templater.fill('./templates/elements/modal.html', { isActive: 'is-active', content: messageBox, }); - let body = app.fillTemplate('./templates/pages/uploadForm.html', { resourcePath, title, author, summary, contributor }); + let body = app.templater.fill('./templates/pages/uploadForm.html', { resourcePath, title, author, summary, contributor }); body = app.replaceBodyWithTooManyBooksWarning(body); - const html = app.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, modal }); + const html = app.templater.fill('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, modal }); res.send(html); }); } else { @@ -47,14 +47,14 @@ module.exports = function (app) { if (!req.body.hasOwnProperty('summary') || req.body.summary.trim() === '') { errorMessage += (errorMessage.length > 0 ? '
' : '') + 'You have not written a summary.'; } - const message = app.fillTemplate('./templates/elements/messageBox.html', { + const message = app.templater.fill('./templates/elements/messageBox.html', { style: 'is-danger', header: 'Missing Required Fields', message: errorMessage, }); - let body = app.fillTemplate('./templates/pages/uploadForm.html', { resourcePath, title, author, summary, contributor }); + let body = app.templater.fill('./templates/pages/uploadForm.html', { resourcePath, title, author, summary, contributor }); body = app.replaceBodyWithTooManyBooksWarning(body); - const html = app.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, message }); + const html = app.templater.fill('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, message }); res.send(html); } }); diff --git a/routes/post_tools.js b/routes/post_tools.js index 6df2802..ae15566 100644 --- a/routes/post_tools.js +++ b/routes/post_tools.js @@ -5,7 +5,7 @@ module.exports = function (app) { app.server.post('/tools', (req, res) => { if (req.query.pass === settings.toolsPassword) { const templateValues = {}; - let html = app.fillTemplate('./templates/pages/tools.html', templateValues); + let html = app.templater.fill('./templates/pages/tools.html', templateValues); const { files } = req; if (Object.keys(files).length > 0) { @@ -17,7 +17,7 @@ module.exports = function (app) { if (err) { console.error(error); templateValues[backupType + 'UploadSuccess'] = 'Could not upload the file.'; - html = app.fillTemplate('./templates/pages/tools.html', templateValues); + html = app.templater.fill('./templates/pages/tools.html', templateValues); res.send(html); } else { onezip.extract(uploadPath, path.resolve('./public', backupType)) @@ -27,12 +27,12 @@ module.exports = function (app) { .on('error', (error) => { console.error(error); templateValues[backupType + 'UploadSuccess'] = 'Something went wrong: ' + JSON.stringify(error); - html = app.fillTemplate('./templates/pages/tools.html', templateValues); + html = app.templater.fill('./templates/pages/tools.html', templateValues); res.send(html); }) .on('end', () => { templateValues[backupType + 'UploadSuccess'] = 'Uploaded Successfully!'; - html = app.fillTemplate('./templates/pages/tools.html', templateValues); + html = app.templater.fill('./templates/pages/tools.html', templateValues); res.send(html); fs.unlink(uploadPath, (err) => { if (err) { @@ -46,7 +46,7 @@ module.exports = function (app) { }); } else { templateValues['generalError'] = '

' + backupType + ' is not a valid backup type.

'; - html = app.fillTemplate('./templates/pages/tools.html', templateValues); + html = app.templater.fill('./templates/pages/tools.html', templateValues); res.send(html); } } else { diff --git a/server.js b/server.js index 19b7375..31de42f 100644 --- a/server.js +++ b/server.js @@ -13,6 +13,8 @@ const privateKey = settings.sslPrivateKey ? fs.readFileSync(settings.sslPrivateK const certificate = settings.sslCertificate ? fs.readFileSync(settings.sslCertificate, 'utf8') : null; const ca = settings.sslCertificateAuthority ? fs.readFileSync(settings.sslCertificateAuthority, 'utf8') : null; +const Templater = require('./templates/Templater'); + function Server () { this.server = express(); this.http = http.Server(this.server); @@ -28,7 +30,7 @@ function Server () { this.fileLocation = path.resolve(settings.fileLocation); this.historyLocation = path.resolve(settings.historyLocation); - this.templateCache = {}; + this.templater = new Templater(this); this.connections = 0; this.takenBooks = []; @@ -50,42 +52,11 @@ function Server () { require('./routes/socketio')(this); } -Server.prototype.fillTemplate = function (file, templateVars = {}) { - let data; - if (this.templateCache.hasOwnProperty(file)) { - data = this.templateCache[file]; - } else { - data = fs.readFileSync(path.resolve(file), 'utf8'); - } - if (data) { - if (!this.templateCache.hasOwnProperty(file)) { - this.templateCache[file] = data; - } - - let filledTemplate = data.replace(/\{\{siteTitle\}\}/g, settings.siteTitle) - .replace(/\{\{titleSeparator\}\}/g, settings.titleSeparator) - .replace(/\{\{allowedFormats\}\}/g, settings.allowedFormats.join(',')) - .replace(/\{\{maxFileSize\}\}/g, (settings.maxFileSize > 0 ? settings.maxFileSize + 'MB' : 'no')); - - for (let templateVar in templateVars) { - const regExp = new RegExp('\{\{' + templateVar + '\}\}', 'g') - filledTemplate = filledTemplate.replace(regExp, templateVars[templateVar]); - } - - // If any template variable is not provided, don't even render them. - filledTemplate = filledTemplate.replace(/\{\{[a-zA-Z0-9\-_]+\}\}/g, ''); - - return filledTemplate; - } - - return data; -} - Server.prototype.replaceBodyWithTooManyBooksWarning = function (body) { if (settings.maxLibrarySize > 0) { const numberOfBooks = fs.readdirSync(this.fileLocation).filter(fileName => fileName.includes('.json')).length; if (numberOfBooks >= settings.maxLibrarySize) { - body = this.fillTemplate('./templates/elements/messageBox.html', { + body = this.templater.fill('./templates/elements/messageBox.html', { style: 'is-danger', title: 'Library Full', message: 'Sorry, the library has reached its maximum capacity for books! You will need to wait until a book is taken before a new one can be added.', diff --git a/templates/Templater.js b/templates/Templater.js new file mode 100644 index 0000000..0848551 --- /dev/null +++ b/templates/Templater.js @@ -0,0 +1,42 @@ +const path = require('path'); +const fs = require('fs'); + +const settings = require('../settings.json'); + +module.exports = class { + constructor (app) { + this.app = app; + this.cache = {}; + } + + fill (file, templateVars = {}) { + let data; + if (this.cache.hasOwnProperty(file)) { + data = this.cache[file]; + } else { + data = fs.readFileSync(path.resolve(file), 'utf8'); + } + if (data) { + if (!this.cache.hasOwnProperty(file)) { + this.cache[file] = data; + } + + let filledTemplate = data.replace(/\{\{siteTitle\}\}/g, settings.siteTitle) + .replace(/\{\{titleSeparator\}\}/g, settings.titleSeparator) + .replace(/\{\{allowedFormats\}\}/g, settings.allowedFormats.join(',')) + .replace(/\{\{maxFileSize\}\}/g, (settings.maxFileSize > 0 ? settings.maxFileSize + 'MB' : 'no')); + + for (let templateVar in templateVars) { + const regExp = new RegExp('\{\{' + templateVar + '\}\}', 'g') + filledTemplate = filledTemplate.replace(regExp, templateVars[templateVar]); + } + + // If any template variable is not provided, don't even render them. + filledTemplate = filledTemplate.replace(/\{\{[a-zA-Z0-9\-_]+\}\}/g, ''); + + return filledTemplate; + } + + return data; + } +} \ No newline at end of file