diff --git a/routes/get_about.js b/routes/get_about.js
new file mode 100644
index 0000000..130eda4
--- /dev/null
+++ b/routes/get_about.js
@@ -0,0 +1,12 @@
+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 });
+ if (html) {
+ res.send(html);
+ } else {
+ res.send('Something went wrong!');
+ }
+ });
+}
\ No newline at end of file
diff --git a/routes/get_give.js b/routes/get_give.js
new file mode 100644
index 0000000..ad93bc1
--- /dev/null
+++ b/routes/get_give.js
@@ -0,0 +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 });
+ body = app.replaceBodyWithTooManyBooksWarning(body);
+
+ const html = app.fillTemplate('./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
new file mode 100644
index 0000000..a743183
--- /dev/null
+++ b/routes/get_history.js
@@ -0,0 +1,59 @@
+const path = require('path');
+const fs = require('fs');
+const snarkdown = require('snarkdown');
+const fecha = require('fecha');
+
+module.exports = function (app) {
+ app.server.get('/history', (req, res) => {
+ const files = fs.readdirSync(app.historyLocation).filter(fileName => fileName.includes('.json'))
+ .map(fileName => { // Cache the file data so sorting doesn't need to re-check each file
+ return { name: fileName, time: fs.statSync(path.resolve(app.historyLocation, fileName)).mtime.getTime() };
+ }).sort((a, b) => b.time - a.time).map(v => v.name); // Sort from newest to oldest.
+
+ let history = files.map(fileName => {
+ const bookData = JSON.parse(fs.readFileSync(path.resolve(app.historyLocation, fileName), 'utf8'));
+ bookData.author = bookData.author ? bookData.author : 'author not provided';
+ bookData.contributor = bookData.contributor ? bookData.contributor : 'Anonymous';
+ const id = fileName.replace('.json', '');
+ 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 = '
';
+ const modal = app.fillTemplate('./templates/elements/modalCard.html', {
+ id,
+ header: '' + bookData.title + '
' + bookData.author + '
',
+ content: app.fillTemplate('./templates/elements/bookInfo.html', {
+ contributor: bookData.contributor,
+ fileFormat: bookData.fileType,
+ added,
+ removedTag,
+ summary: snarkdown(bookData.summary),
+ }),
+ footer: 'Close',
+ });
+ return app.fillTemplate('./templates/elements/book.html', {
+ id,
+ title: bookData.title,
+ author: bookData.author,
+ fileType: bookData.fileType,
+ modal,
+ });
+ }).join('');
+
+ if (history == '') {
+ history = 'No books have been taken yet. Would you like to
take a book?
';
+ }
+
+ const body = 'History
' + history + '
';
+ const html = app.fillTemplate('./templates/htmlContainer.html', {
+ title: 'History',
+ resourcePath: (req.url.substr(-1) === '/' ? '../' : './'),
+ body
+ });
+
+ if (html) {
+ res.send(html);
+ } else {
+ res.send('Something went wrong!');
+ }
+ });
+}
\ No newline at end of file
diff --git a/routes/get_home.js b/routes/get_home.js
new file mode 100644
index 0000000..43bada1
--- /dev/null
+++ b/routes/get_home.js
@@ -0,0 +1,66 @@
+const path = require('path');
+const fs = require('fs');
+const snarkdown = require('snarkdown');
+const fecha = require('fecha');
+
+module.exports = function (app) {
+ app.server.get('/', (req, res) => {
+ const files = fs.readdirSync(app.fileLocation).filter(fileName => fileName.includes('.json'))
+ .map(fileName => { // Cache the file data so sorting doesn't need to re-check each file
+ return { name: fileName, time: fs.statSync(path.resolve(app.fileLocation, fileName)).mtime.getTime() };
+ }).sort((a, b) => a.time - b.time).map(v => v.name); // Sort from oldest to newest.
+
+ let books = files.map(fileName => {
+ const bookData = JSON.parse(fs.readFileSync(path.resolve(app.fileLocation, fileName), 'utf8'));
+ if (bookData.hasOwnProperty('fileName')) return '';
+ bookData.author = bookData.author ? bookData.author : 'author not provided';
+ bookData.contributor = bookData.contributor ? bookData.contributor : 'Anonymous';
+
+ 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', {
+ id,
+ header: '' + bookData.title + '
' + bookData.author + '
',
+ content: app.fillTemplate('./templates/elements/bookInfo.html', {
+ contributor: bookData.contributor,
+ fileFormat: bookData.fileType,
+ added,
+ summary: snarkdown(bookData.summary),
+ })
+ + app.fillTemplate('./templates/elements/modal.html', {
+ id: confirmId,
+ content: app.fillTemplate('./templates/elements/messageBox.html', {
+ header: 'Download Your Book',
+ message: app.fillTemplate('./templates/elements/takeConfirm.html', { id }),
+ }),
+ }),
+ footer: 'Close Take Book',
+ });
+ return app.fillTemplate('./templates/elements/book.html', {
+ id,
+ title: bookData.title,
+ author: bookData.author,
+ fileType: bookData.fileType,
+ modal,
+ });
+ }).join('');
+
+ if (books == '') {
+ books = '';
+ }
+
+ const body = 'Available Books
' + books + '
';
+ const html = app.fillTemplate('./templates/htmlContainer.html', {
+ title: 'View',
+ resourcePath: (req.url.substr(-1) === '/' ? '../' : './'),
+ body
+ });
+
+ if (html) {
+ res.send(html);
+ } else {
+ res.send('Something went wrong!');
+ }
+ });
+}
\ No newline at end of file
diff --git a/routes/get_tools.js b/routes/get_tools.js
new file mode 100644
index 0000000..62eaa80
--- /dev/null
+++ b/routes/get_tools.js
@@ -0,0 +1,56 @@
+const path = require('path');
+const fs = require('fs');
+
+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);
+
+ if (req.query.do && ['resetVisitors'].includes(req.query.do)) {
+ app.connections = 0;
+ templateValues.resetVisitors = 'Done!';
+ html = app.fillTemplate('./templates/pages/tools.html', templateValues);
+ res.send(html);
+ } else if (req.query.dl && ['files', 'history'].includes(req.query.dl)) {
+ const onezip = require('onezip');
+ const { dl } = req.query;
+ const saveLocation = path.resolve(app.fileLocation, dl + 'Backup.zip');
+ const backupLocation = dl === 'history' ? app.historyLocation : app.fileLocation;
+ const files = fs.readdirSync(backupLocation).filter(fileName => !fileName.includes('.zip'));
+ onezip.pack(backupLocation, saveLocation, files)
+ .on('start', () => {
+ console.info('Starting a backup zip of ' + dl)
+ })
+ .on('error', (error) => {
+ console.error(error);
+ templateValues[dl + 'Download'] = 'Something went wrong: ' + JSON.stringify(error);
+ html = app.fillTemplate('./templates/pages/tools.html', templateValues);
+ res.send(html);
+ })
+ .on('end', () => {
+ console.log('Backup complete. Saved to ' + saveLocation);
+ 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);
+ res.send(html);
+ console.log('Will delete ' + saveLocation + ' in 1 hour');
+ setTimeout(() => {
+ fs.unlink(saveLocation, (err) => {
+ if (err) {
+ console.error(err);
+ } else {
+ console.log('Deleted backup file ' + saveLocation);
+ }
+ })
+ }, 60 * 60 * 1000);
+ });
+ } else {
+ res.send(html);
+ }
+ } else {
+ res.status(400).send();
+ }
+ });
+}
\ No newline at end of file
diff --git a/routes/middleware.js b/routes/middleware.js
new file mode 100644
index 0000000..68a2d46
--- /dev/null
+++ b/routes/middleware.js
@@ -0,0 +1,43 @@
+const path = require('path');
+const fs = require('fs');
+const express = require('express');
+const helmet = require('helmet');
+const bodyParser = require('body-parser');
+const fileUpload = require('express-fileupload');
+
+const settings = require('../settings.json');
+
+module.exports = function (app) {
+ app.server.use(helmet());
+
+ app.server.use(bodyParser.json()); // support json encoded bodies
+ app.server.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
+
+ app.server.use('/give', fileUpload({ // support file uploads
+ limits: {
+ fileSize: (settings.maxFileSize > 0 ? settings.maxFileSize * 1024 * 1024 : Infinity), // filesize in bytes (settings accepts MB)
+ },
+ }));
+ app.server.use('/tools', fileUpload()); // Allow file upload on backup with no limits.
+
+ app.server.use('/files', express.static(path.resolve('./public/files/')));
+ app.server.use('/css', express.static(path.resolve('./node_modules/bulma/css/')));
+ app.server.use('/css', express.static(path.resolve('./public/css/')));
+ app.server.use('/js', express.static(path.resolve('./public/js/')));
+ app.server.use('/js', express.static(path.resolve('./node_modules/jquery/dist/')));
+ app.server.use('/js', express.static(path.resolve('./node_modules/socket.io-client/dist/')));
+
+ // If a `.well-known` directory exists, allow it to be used for things like Let's Encrypt challenges
+ if (fs.existsSync(path.resolve('./.well-known'))) {
+ app.server.use('/.well-known', express.static(path.resolve('./.well-known')));
+ }
+
+ if (app.https && settings.forceHTTPS) {
+ app.server.use(function (req, res, next) {
+ if (!req.secure) {
+ return res.redirect(['https://', req.get('Host'), req.baseUrl].join(''));
+ }
+ next(); 0
+ });
+ }
+}
\ No newline at end of file
diff --git a/routes/post_give.js b/routes/post_give.js
new file mode 100644
index 0000000..6563663
--- /dev/null
+++ b/routes/post_give.js
@@ -0,0 +1,61 @@
+module.exports = function (app) {
+ app.server.post('/give', (req, res) => {
+ const resourcePath = (req.url.substr(-1) === '/' ? '../' : './');
+ const { title, author, summary, contributor } = req.body;
+ if (Object.keys(req.files).length > 0
+ && req.body.hasOwnProperty('title') && title.trim() !== ''
+ && req.body.hasOwnProperty('summary') && summary.trim() !== '') {
+ 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', {
+ style: 'is-success',
+ header: 'Upload Successful',
+ message: 'Thank you for your contribution!'
+ });
+ const modal = app.fillTemplate('./templates/elements/modal.html', {
+ isActive: 'is-active',
+ content: messageBox,
+ });
+ let body = app.fillTemplate('./templates/pages/uploadForm.html', { resourcePath });
+ body = app.replaceBodyWithTooManyBooksWarning(body);
+ const html = app.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, modal });
+ res.send(html);
+ }, (err) => {
+ const messageBox = app.fillTemplate('./templates/elements/messageBox.html', {
+ style: 'is-danger',
+ header: 'Upload Failed',
+ message: err,
+ });
+ const modal = app.fillTemplate('./templates/elements/modal.html', {
+ isActive: 'is-active',
+ content: messageBox,
+ });
+ let body = app.fillTemplate('./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 });
+ res.send(html);
+ });
+ } else {
+ let errorMessage = '';
+ if (Object.keys(req.files).length <= 0) {
+ errorMessage += 'You have not selected a file.';
+ }
+ if (!req.body.hasOwnProperty('title') || req.body.title.trim() === '') {
+ errorMessage += (errorMessage.length > 0 ? '
' : '') + 'You have not written a title.';
+ }
+ 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', {
+ style: 'is-danger',
+ header: 'Missing Required Fields',
+ message: errorMessage,
+ });
+ let body = app.fillTemplate('./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 });
+ res.send(html);
+ }
+ });
+}
\ No newline at end of file
diff --git a/routes/post_tools.js b/routes/post_tools.js
new file mode 100644
index 0000000..6df2802
--- /dev/null
+++ b/routes/post_tools.js
@@ -0,0 +1,59 @@
+const path = require('path');
+const fs = require('fs');
+
+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);
+
+ const { files } = req;
+ if (Object.keys(files).length > 0) {
+ const backupType = Object.keys(files)[0];
+ if (['files', 'history'].includes(backupType)) {
+ const onezip = require('onezip');
+ const uploadPath = path.resolve('./', backupType + 'UploadedBackup.zip');
+ files[backupType].mv(uploadPath, (err) => {
+ if (err) {
+ console.error(error);
+ templateValues[backupType + 'UploadSuccess'] = 'Could not upload the file.';
+ html = app.fillTemplate('./templates/pages/tools.html', templateValues);
+ res.send(html);
+ } else {
+ onezip.extract(uploadPath, path.resolve('./public', backupType))
+ .on('start', () => {
+ console.info('Extracting file ' + uploadPath)
+ })
+ .on('error', (error) => {
+ console.error(error);
+ templateValues[backupType + 'UploadSuccess'] = 'Something went wrong: ' + JSON.stringify(error);
+ html = app.fillTemplate('./templates/pages/tools.html', templateValues);
+ res.send(html);
+ })
+ .on('end', () => {
+ templateValues[backupType + 'UploadSuccess'] = 'Uploaded Successfully!';
+ html = app.fillTemplate('./templates/pages/tools.html', templateValues);
+ res.send(html);
+ fs.unlink(uploadPath, (err) => {
+ if (err) {
+ console.error(err);
+ } else {
+ console.log('Deleted backup file ' + uploadPath);
+ }
+ })
+ });
+ }
+ });
+ } else {
+ templateValues['generalError'] = '' + backupType + ' is not a valid backup type.
';
+ html = app.fillTemplate('./templates/pages/tools.html', templateValues);
+ res.send(html);
+ }
+ } else {
+ res.send(html);
+ }
+ } else {
+ res.status(400).send();
+ }
+ });
+}
\ No newline at end of file
diff --git a/routes/socketio.js b/routes/socketio.js
new file mode 100644
index 0000000..b8e8967
--- /dev/null
+++ b/routes/socketio.js
@@ -0,0 +1,29 @@
+const settings = require('../settings.json');
+
+module.exports = function (app) {
+ app.io.on('connection', socket => {
+ if (!settings.hideVisitors) {
+ app.connections++;
+ app.io.emit('update visitors', app.connections);
+ }
+
+ socket.on('take book', bookId => {
+ const fileLocation = app.takeBook(bookId, socket.id);
+ if (fileLocation) {
+ console.log(socket.id + ' removed ' + bookId);
+ const downloadLocation = fileLocation.substr(fileLocation.lastIndexOf('/'));
+ socket.emit('get book', encodeURI('./files' + downloadLocation));
+ socket.broadcast.emit('remove book', bookId);
+ }
+ });
+
+ socket.on('disconnect', () => {
+ if (!settings.hideVisitors) {
+ app.connections--;
+ if (app.connections < 0) app.connections = 0;
+ app.io.emit('update visitors', app.connections);
+ }
+ app.deleteBooks(socket.id);
+ });
+ });
+}
\ No newline at end of file
diff --git a/server.js b/server.js
index 07e3da4..19b7375 100644
--- a/server.js
+++ b/server.js
@@ -4,14 +4,9 @@ const express = require('express');
const http = require('http');
const https = require('https');
const SocketIoServer = require('socket.io');
-const helmet = require('helmet');
-const bodyParser = require('body-parser');
-const fileUpload = require('express-fileupload');
const filenamify = require('filenamify');
const unusedFilename = require('unused-filename');
const striptags = require('striptags');
-const snarkdown = require('snarkdown');
-const fecha = require('fecha');
const settings = require('./settings.json');
const privateKey = settings.sslPrivateKey ? fs.readFileSync(settings.sslPrivateKey, 'utf8') : null;
@@ -38,267 +33,21 @@ function Server () {
this.connections = 0;
this.takenBooks = [];
- this.server.use(helmet());
+ require('./routes/middleware')(this);
- this.server.use(bodyParser.json()); // support json encoded bodies
- this.server.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
+ require('./routes/get_home')(this);
- this.server.use('/give', fileUpload({ // support file uploads
- limits: {
- fileSize: (settings.maxFileSize > 0 ? settings.maxFileSize * 1024 * 1024 : Infinity), // filesize in bytes (settings accepts MB)
- },
- }));
- this.server.use('/tools', fileUpload()); // Allow file upload on backup with no limits.
+ require('./routes/get_give')(this);
+ require('./routes/post_give')(this);
- this.server.use('/files', express.static(path.join(__dirname, './public/files/')));
- this.server.use('/css', express.static(path.resolve('./node_modules/bulma/css/')));
- this.server.use('/css', express.static(path.join(__dirname, './public/css/')));
- this.server.use('/js', express.static(path.join(__dirname, './public/js/')));
- this.server.use('/js', express.static(path.resolve('./node_modules/jquery/dist/')));
- this.server.use('/js', express.static(path.resolve('./node_modules/socket.io-client/dist/')));
+ require('./routes/get_history')(this);
- // If a `.well-known` directory exists, allow it to be used for things like Let's Encrypt challenges
- if (fs.existsSync(path.resolve('./.well-known'))) {
- this.server.use('/.well-known', express.static(path.resolve('./.well-known')));
- }
+ require('./routes/get_about')(this);
- if (this.https && settings.forceHTTPS) {
- this.server.use(function (req, res, next) {
- if (!req.secure) {
- return res.redirect(['https://', req.get('Host'), req.baseUrl].join(''));
- }
- next();0
- });
- }
-
- this.server.get('/', (req, res) => {
- const html = this.generateHomePage(req);
- if (html) {
- res.send(html);
- } else {
- res.send('Something went wrong!');
- }
- });
+ require('./routes/get_tools')(this);
+ require('./routes/post_tools')(this);
- this.server.get('/give', (req, res) => {
- const resourcePath = (req.url.substr(-1) === '/' ? '../' : './');
- let body = this.fillTemplate('./templates/pages/uploadForm.html', { resourcePath });
- body = this.replaceBodyWithTooManyBooksWarning(body);
-
- const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body });
- res.send(html);
- });
- this.server.post('/give', (req, res) => {
- const resourcePath = (req.url.substr(-1) === '/' ? '../' : './');
- const { title, author, summary, contributor } = req.body;
- if (Object.keys(req.files).length > 0
- && req.body.hasOwnProperty('title') && title.trim() !== ''
- && req.body.hasOwnProperty('summary') && summary.trim() !== '') {
- const { book } = req.files;
- const fileType = book.name.substr(book.name.lastIndexOf('.'));
- this.addBook({ book, title, author, summary, contributor, fileType }, () => {
- const messageBox = this.fillTemplate('./templates/elements/messageBox.html', {
- style: 'is-success',
- header: 'Upload Successful',
- message: 'Thank you for your contribution!'
- });
- const modal = this.fillTemplate('./templates/elements/modal.html', {
- isActive: 'is-active',
- content: messageBox,
- });
- let body = this.fillTemplate('./templates/pages/uploadForm.html', { resourcePath });
- body = this.replaceBodyWithTooManyBooksWarning(body);
- const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, modal });
- res.send(html);
- }, (err) => {
- const messageBox = this.fillTemplate('./templates/elements/messageBox.html', {
- style: 'is-danger',
- header: 'Upload Failed',
- message: err,
- });
- const modal = this.fillTemplate('./templates/elements/modal.html', {
- isActive: 'is-active',
- content: messageBox,
- });
- let body = this.fillTemplate('./templates/pages/uploadForm.html', { resourcePath, title, author, summary, contributor });
- body = this.replaceBodyWithTooManyBooksWarning(body);
- const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, modal });
- res.send(html);
- });
- } else {
- let errorMessage = '';
- if (Object.keys(req.files).length <= 0) {
- errorMessage += 'You have not selected a file.';
- }
- if (!req.body.hasOwnProperty('title') || req.body.title.trim() === '') {
- errorMessage += (errorMessage.length > 0 ? '
' : '') + 'You have not written a title.';
- }
- if (!req.body.hasOwnProperty('summary') || req.body.summary.trim() === '') {
- errorMessage += (errorMessage.length > 0 ? '
' : '') + 'You have not written a summary.';
- }
- const message = this.fillTemplate('./templates/elements/messageBox.html', {
- style: 'is-danger',
- header: 'Missing Required Fields',
- message: errorMessage,
- });
- let body = this.fillTemplate('./templates/pages/uploadForm.html', { resourcePath, title, author, summary, contributor });
- body = this.replaceBodyWithTooManyBooksWarning(body);
- const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'Give a Book', resourcePath, body, message });
- res.send(html);
- }
- });
-
- this.server.get('/history', (req, res) => {
- const html = this.generateHistoryPage(req);
- if (html) {
- res.send(html);
- } else {
- res.send('Something went wrong!');
- }
- });
-
- this.server.get('/about', (req, res) => {
- const resourcePath = (req.url.substr(-1) === '/' ? '../' : './');
- const body = this.fillTemplate('./templates/pages/about.html', { resourcePath });
- const html = this.fillTemplate('./templates/htmlContainer.html', { title: 'About', body });
- if (html) {
- res.send(html);
- } else {
- res.send('Something went wrong!');
- }
- });
-
- this.server.get('/tools', (req, res) => {
- if (req.query.pass === settings.toolsPassword) {
- const templateValues = {};
- let html = this.fillTemplate('./templates/pages/tools.html', templateValues);
-
- if (req.query.do && ['resetVisitors'].includes(req.query.do)) {
- this.connections = 0;
- templateValues.resetVisitors = 'Done!';
- html = this.fillTemplate('./templates/pages/tools.html', templateValues);
- res.send(html);
- } else if (req.query.dl && ['files', 'history'].includes(req.query.dl)) {
- const onezip = require('onezip');
- const { dl } = req.query;
- const saveLocation = path.resolve(this.fileLocation, dl + 'Backup.zip');
- const backupLocation = dl === 'history' ? this.historyLocation : this.fileLocation;
- const files = fs.readdirSync(backupLocation).filter(fileName => !fileName.includes('.zip'));
- onezip.pack(backupLocation, saveLocation, files)
- .on('start', () => {
- console.info('Starting a backup zip of ' + dl)
- })
- .on('error', (error) => {
- console.error(error);
- templateValues[dl + 'Download'] = 'Something went wrong: ' + JSON.stringify(error);
- html = this.fillTemplate('./templates/pages/tools.html', templateValues);
- res.send(html);
- })
- .on('end', () => {
- console.log('Backup complete. Saved to ' + saveLocation);
- 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 = this.fillTemplate('./templates/pages/tools.html', templateValues);
- res.send(html);
- console.log('Will delete ' + saveLocation + ' in 1 hour');
- setTimeout(() => {
- fs.unlink(saveLocation, (err) => {
- if (err) {
- console.error(err);
- } else {
- console.log('Deleted backup file ' + saveLocation);
- }
- })
- }, 60 * 60 * 1000);
- });
- } else {
- res.send(html);
- }
- } else {
- res.status(400).send();
- }
- });
- this.server.post('/tools', (req, res) => {
- if (req.query.pass === settings.toolsPassword) {
- const templateValues = {};
- let html = this.fillTemplate('./templates/pages/tools.html', templateValues);
-
- const { files } = req;
- if (Object.keys(files).length > 0) {
- const backupType = Object.keys(files)[0];
- if (['files', 'history'].includes(backupType)) {
- const onezip = require('onezip');
- const uploadPath = path.resolve('./', backupType + 'UploadedBackup.zip');
- files[backupType].mv(uploadPath, (err) => {
- if (err) {
- console.error(error);
- templateValues[backupType + 'UploadSuccess'] = 'Could not upload the file.';
- html = this.fillTemplate('./templates/pages/tools.html', templateValues);
- res.send(html);
- } else {
- onezip.extract(uploadPath, path.resolve('./public', backupType))
- .on('start', () => {
- console.info('Extracting file ' + uploadPath)
- })
- .on('error', (error) => {
- console.error(error);
- templateValues[backupType + 'UploadSuccess'] = 'Something went wrong: ' + JSON.stringify(error);
- html = this.fillTemplate('./templates/pages/tools.html', templateValues);
- res.send(html);
- })
- .on('end', () => {
- templateValues[backupType + 'UploadSuccess'] = 'Uploaded Successfully!';
- html = this.fillTemplate('./templates/pages/tools.html', templateValues);
- res.send(html);
- fs.unlink(uploadPath, (err) => {
- if (err) {
- console.error(err);
- } else {
- console.log('Deleted backup file ' + uploadPath);
- }
- })
- });
- }
- });
- } else {
- templateValues['generalError'] = '' + backupType + ' is not a valid backup type.
';
- html = this.fillTemplate('./templates/pages/tools.html', templateValues);
- res.send(html);
- }
- } else {
- res.send(html);
- }
- } else {
- res.status(400).send();
- }
- });
-
- this.io.on('connection', socket => {
- if (!settings.hideVisitors) {
- this.connections++;
- this.io.emit('update visitors', this.connections);
- }
-
- socket.on('take book', bookId => {
- const fileLocation = this.takeBook(bookId, socket.id);
- if (fileLocation) {
- console.log(socket.id + ' removed ' + bookId);
- const downloadLocation = fileLocation.substr(fileLocation.lastIndexOf('/'));
- socket.emit('get book', encodeURI('./files' + downloadLocation));
- socket.broadcast.emit('remove book', bookId);
- }
- });
-
- socket.on('disconnect', () => {
- if (!settings.hideVisitors) {
- this.connections--;
- if (this.connections < 0) this.connections = 0;
- this.io.emit('update visitors', this.connections);
- }
- this.deleteBooks(socket.id);
- });
- });
+ require('./routes/socketio')(this);
}
Server.prototype.fillTemplate = function (file, templateVars = {}) {
@@ -306,7 +55,7 @@ Server.prototype.fillTemplate = function (file, templateVars = {}) {
if (this.templateCache.hasOwnProperty(file)) {
data = this.templateCache[file];
} else {
- data = fs.readFileSync(path.join(__dirname, file), 'utf8');
+ data = fs.readFileSync(path.resolve(file), 'utf8');
}
if (data) {
if (!this.templateCache.hasOwnProperty(file)) {
@@ -347,118 +96,6 @@ Server.prototype.replaceBodyWithTooManyBooksWarning = function (body) {
return body;
}
-Server.prototype.generateHomePage = function (req) {
- const files = fs.readdirSync(this.fileLocation).filter(fileName => fileName.includes('.json'))
- .map(fileName => { // Cache the file data so sorting doesn't need to re-check each file
- return { name: fileName, time: fs.statSync(path.resolve(this.fileLocation, fileName)).mtime.getTime() };
- }).sort((a, b) => a.time - b.time).map(v => v.name); // Sort from oldest to newest.
-
- let books = files.map(fileName => {
- const bookData = JSON.parse(fs.readFileSync(path.resolve(this.fileLocation, fileName), 'utf8'));
- if (bookData.hasOwnProperty('fileName')) return '';
- bookData.author = bookData.author ? bookData.author : 'author not provided';
- bookData.contributor = bookData.contributor ? bookData.contributor : 'Anonymous';
-
- 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 = this.fillTemplate('./templates/elements/modalCard.html', {
- id,
- header: '' + bookData.title + '
' + bookData.author + '
',
- content: this.fillTemplate('./templates/elements/bookInfo.html', {
- contributor: bookData.contributor,
- fileFormat: bookData.fileType,
- added,
- summary: snarkdown(bookData.summary),
- })
- + this.fillTemplate('./templates/elements/modal.html', {
- id: confirmId,
- content: this.fillTemplate('./templates/elements/messageBox.html', {
- header: 'Download Your Book',
- message: this.fillTemplate('./templates/elements/takeConfirm.html', { id }),
- }),
- }),
- footer: 'Close Take Book',
- });
- return this.fillTemplate('./templates/elements/book.html', {
- id,
- title: bookData.title,
- author: bookData.author,
- fileType: bookData.fileType,
- modal,
- });
- }).join('');
-
- if (books == '') {
- books = '';
- }
-
- const body = 'Available Books
' + books + '
';
- return this.fillTemplate('./templates/htmlContainer.html', {
- title: 'View',
- resourcePath: (req.url.substr(-1) === '/' ? '../' : './'),
- body
- });
-}
-
-Server.prototype.generateHistoryPage = function (req) {
- const files = fs.readdirSync(this.historyLocation).filter(fileName => fileName.includes('.json'))
- .map(fileName => { // Cache the file data so sorting doesn't need to re-check each file
- return { name: fileName, time: fs.statSync(path.resolve(this.historyLocation, fileName)).mtime.getTime() };
- }).sort((a, b) => b.time - a.time).map(v => v.name); // Sort from newest to oldest.
-
- let history = files.map(fileName => {
- const bookData = JSON.parse(fs.readFileSync(path.resolve(this.historyLocation, fileName), 'utf8'));
- bookData.author = bookData.author ? bookData.author : 'author not provided';
- bookData.contributor = bookData.contributor ? bookData.contributor : 'Anonymous';
- const id = fileName.replace('.json', '');
- 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 = '';
- const modal = this.fillTemplate('./templates/elements/modalCard.html', {
- id,
- header: '' + bookData.title + '
' + bookData.author + '
',
- content: this.fillTemplate('./templates/elements/bookInfo.html', {
- contributor: bookData.contributor,
- fileFormat: bookData.fileType,
- added,
- removedTag,
- summary: snarkdown(bookData.summary),
- }),
- footer: 'Close',
- });
- return this.fillTemplate('./templates/elements/book.html', {
- id,
- title: bookData.title,
- author: bookData.author,
- fileType: bookData.fileType,
- modal,
- });
- }).join('');
-
- if (history == '') {
- history = 'No books have been taken yet. Would you like to
take a book?
';
- }
-
- const body = 'History
' + history + '
';
- return this.fillTemplate('./templates/htmlContainer.html', {
- title: 'History',
- resourcePath: (req.url.substr(-1) === '/' ? '../' : './'),
- body
- });
-}
-
-Server.prototype.start = function () {
- this.http.listen((process.env.PORT || settings.port), () => {
- console.log('Started server on port ' + (process.env.PORT || settings.port));
- });
- if (this.https) {
- this.https.listen(443, () => {
- console.log('Started SSL server on port 443');
- });
- }
-}
-
Server.prototype.addBook = function (uploadData = {}, success = () => {}, error = () => {}) {
const { book } = uploadData;
@@ -568,5 +205,16 @@ Server.prototype.uuid4 = function () {
});
}
+Server.prototype.start = function () {
+ this.http.listen((process.env.PORT || settings.port), () => {
+ console.log('Started server on port ' + (process.env.PORT || settings.port));
+ });
+ if (this.https) {
+ this.https.listen(443, () => {
+ console.log('Started SSL server on port 443');
+ });
+ }
+}
+
const server = new Server();
server.start();