Browse Source

Add History page

activitypub
Robbie Antenesse 3 years ago
parent
commit
d7e77dc4dc
  1. 1
      package.json
  2. 88
      server.js
  3. 1
      settings.json
  4. 24
      templates/elements/bookInfo.html
  5. 7
      templates/elements/takeConfirm.html
  6. 14
      templates/htmlContainer.html
  7. 3
      templates/pages/booksList.html
  8. 5
      yarn.lock

1
package.json

@ -14,6 +14,7 @@
"bulma": "^0.7.2",
"express": "^4.16.4",
"express-fileupload": "^1.0.0",
"fecha": "^3.0.2",
"filenamify": "^2.1.0",
"helmet": "^3.15.0",
"jquery": "^3.3.1",

88
server.js

@ -9,6 +9,7 @@ const fileUpload = require('express-fileupload');
const filenamify = require('filenamify');
const unusedFilename = require('unused-filename');
const snarkdown = require('snarkdown');
const fecha = require('fecha');
const settings = require('./settings.json');
@ -37,12 +38,11 @@ function Server () {
}));
this.server.use('/files', express.static(path.join(__dirname, './public/files/')));
this.server.use('/history', express.static(path.join(__dirname, './public/history/')));
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/')));
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.get('/', (req, res) => {
const html = this.generateHomePage();
@ -114,6 +114,15 @@ function Server () {
}
});
this.server.get('/history', (req, res) => {
const html = this.generateHistoryPage();
if (html) {
res.send(html);
} else {
res.send('Something went wrong!');
}
});
this.io.on('connection', socket => {
this.broadcastVisitors();
@ -171,27 +180,25 @@ Server.prototype.generateHomePage = function () {
if (bookData.hasOwnProperty('fileName')) return '';
const id = fileName.replace('.json', '');
const header = '<h2 class="title">' + bookData.title + '</h2><h4 class="subtitle">' + bookData.author + '</h4>';
const content = '<div class="content"><h4>Contributed by ' + bookData.contributor + '</h4>' + snarkdown(bookData.summary) + '</div>'
+ this.fillTemplate('./templates/elements/modal.html', {
id: 'confirm_' + id,
content: this.fillTemplate('./templates/elements/messageBox.html', {
header: 'Download Your Book',
message: '<div class="content">'
+ '<p class="has-text-weight-bold">Please ensure that you\'re using a device that can download and save the file correctly!</p>'
+ '</div>'
+ '<div class="notification is-danger">After you leave or refresh this page, it will no longer be accessible to anyone!</div>'
+ '<div class="buttons">'
+ '<a class="button close">Cancel</a> <a class="button is-info take-book" data-book="' + id + '">I understand, give me the link!</a>'
+ '</div>',
}),
});
const footer = '<a class="button close">Close</a> <a class="button is-success modal-button" data-modal="confirm_' + id + '">Take Book</a>';
const confirmId = 'confirm_' + id;
const added = fecha.format(new Date(bookData.added), 'dddd MMMM Do, YYYY');
const modal = this.fillTemplate('./templates/elements/modalCard.html', {
id,
header,
content,
footer,
header: '<h2 class="title">' + bookData.title + '</h2><h4 class="subtitle">' + bookData.author + '</h4>',
content: this.fillTemplate('./templates/elements/bookInfo.html', {
contributor: bookData.contributor,
fileFormat: bookData.fileFormat,
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: '<a class="button close">Close</a> <a class="button is-success modal-button" data-modal="' + confirmId + '">Take Book</a>',
});
return this.fillTemplate('./templates/elements/book.html', {
id,
@ -201,10 +208,42 @@ Server.prototype.generateHomePage = function () {
modal,
});
}).join('');
const body = this.fillTemplate('./templates/pages/booksList.html', { books });
const body = '<div class="columns is-multiline">' + books + '</div>';
return this.fillTemplate('./templates/htmlContainer.html', { title: 'View', body });
}
Server.prototype.generateHistoryPage = function () {
const files = fs.readdirSync(this.historyLocation).filter(fileName => fileName.includes('.json'));
const history = files.map(fileName => {
const bookData = JSON.parse(fs.readFileSync(path.resolve(this.historyLocation, fileName), 'utf8'));
const id = fileName.replace('.json', '');
const added = fecha.format(new Date(bookData.added), 'dddd MMMM Do, YYYY');
const removed = fecha.format(new Date(parseInt(id)), '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 modal = this.fillTemplate('./templates/elements/modalCard.html', {
id,
header: '<h2 class="title">' + bookData.title + '</h2><h4 class="subtitle">' + bookData.author + '</h4>',
content: this.fillTemplate('./templates/elements/bookInfo.html', {
contributor: bookData.contributor,
fileFormat: bookData.fileType,
added,
removedTag,
summary: snarkdown(bookData.summary),
}),
footer: '<a class="button close">Close</a>',
});
return this.fillTemplate('./templates/elements/book.html', {
id,
title: bookData.title,
author: bookData.author,
fileType: bookData.fileType,
modal,
});
}).join('');
const body = '<div class="columns is-multiline">' + history + '</div>';
return this.fillTemplate('./templates/htmlContainer.html', { title: 'History', resourcePath: '../', body });
}
Server.prototype.broadcastVisitors = function () {
const numberConnected = this.io.of('/').clients().connected.length;
this.io.emit('connected', numberConnected);
@ -226,6 +265,7 @@ Server.prototype.addBook = function (uploadData = {}, success = () => {}, error
author: uploadData.author.trim(),
summary: uploadData.summary.trim(),
contributor: uploadData.contributor.trim(),
added: Date.now(),
fileType: book.name.substr(book.name.lastIndexOf('.')),
}
@ -276,7 +316,7 @@ Server.prototype.deleteBooks = function (socketId) {
if (data.socketId === socketId) {
const check = this.checkId(data.bookId, (bookPath, bookDataPath) => {
fs.unlinkSync(bookPath);
fs.renameSync(bookDataPath, path.resolve(this.historyLocation, data.bookId + '.json'));
fs.renameSync(bookDataPath, unusedFilename.sync(path.resolve(this.historyLocation, Date.now() + '.json')));
});
if (check === false) {
console.log('couldn\'t find data.bookId');

1
settings.json

@ -6,5 +6,6 @@
"historyLocation": "./public/history/",
"maxLibrarySize": 0,
"maxFileSize": 0,
"maxHistory": 0,
"allowedFormats": [".epub", ".mobi", ".pdf"]
}

24
templates/elements/bookInfo.html

@ -0,0 +1,24 @@
<div class="content">
<h4>Contributed by {{contributor}}</h4>
<div class="field is-grouped is-grouped-multiline">
<div class="control">
<div class="tags has-addons">
<span class="tag">File Format</span>
<span class="tag is-primary">{{fileFormat}}</span>
</div>
</div>
<div class="control">
<div class="tags has-addons">
<span class="tag">Added</span>
<span class="tag is-primary">{{added}}</span>
</div>
</div>
{{removedTag}}
</div>
<div class="content">
<p>{{contributor}} said:</p>
{{summary}}
</div>
</div>

7
templates/elements/takeConfirm.html

@ -0,0 +1,7 @@
<div class="content">
<p class="has-text-weight-bold">Please ensure that you're using a device that can download and save the file correctly!</p>
</div>
<div class="notification is-danger">After you leave or refresh this page, it will no longer be accessible to anyone!</div>
<div class="buttons">
<a class="button close">Cancel</a> <a class="button is-info take-book" data-book="{{id}}">I understand, give me the link!</a>
</div>

14
templates/htmlContainer.html

@ -9,11 +9,11 @@
<title>{{title}}{{titleSeparator}}{{siteTitle}}</title>
<meta name="description" content="A digital give-a-book, take-a-book library for ebooks">
<link rel="stylesheet" href="./css/bulma.min.css?v=1.0">
<link rel="stylesheet" href="./css/styles.css?v=1.0">
<link rel="stylesheet" href="{{resourcePath}}css/bulma.min.css?v=1.0">
<link rel="stylesheet" href="{{resourcePath}}css/styles.css?v=1.0">
<script src="./js/jquery.min.js"></script>
<script src="./js/socket.io.js"></script>
<script src="{{resourcePath}}js/jquery.min.js"></script>
<script src="{{resourcePath}}js/socket.io.js"></script>
</head>
<body>
@ -39,6 +39,10 @@
<a class="navbar-item" href="/give">
Give
</a>
<a class="navbar-item" href="/history/">
History
</a>
</div>
<div class="navbar-end">
@ -70,7 +74,7 @@
</footer>
{{modal}}
<script src="./js/little-library.js"></script>
<script src="{{resourcePath}}js/little-library.js"></script>
</body>
</html>

3
templates/pages/booksList.html

@ -1,3 +0,0 @@
<div class="columns is-multiline">
{{books}}
</div>

5
yarn.lock

@ -330,6 +330,11 @@ feature-policy@0.2.0:
resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.2.0.tgz#22096de49ab240176878ffe2bde2f6ff04d48c43"
integrity sha512-2hGrlv6efG4hscYVZeaYjpzpT6I2OZgYqE2yDUzeAcKj2D1SH0AsEzqJNXzdoglEddcIXQQYop3lD97XpG75Jw==
fecha@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/fecha/-/fecha-3.0.2.tgz#fb3adb02762ab6dd27f7d5419f2f6c21a4229cd7"
integrity sha512-oJK6YbKtmz1uvuDsUHOmo9X2HKmYAcRWtzW2yrCzOJRUfyGUEu/8cDymBdedgEnkdJiTpNyPogWqfTuYffU4yA==
filename-reserved-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229"

Loading…
Cancel
Save