From da86f605c6419afb4e12384496afb9ed60812758 Mon Sep 17 00:00:00 2001 From: Bobby Wibowo Date: Thu, 13 Dec 2018 16:09:46 +0700 Subject: [PATCH] Updates [!! run database/migration.js !!] Added description column into albums. So yeah, now albums can have description. It'll only be shown in the album's edit popup and public link. HTML chars will now be escaped from album's name and description. Removed message warning about CDN cache from album's public link. A shortened version will be shown as the download button's tooltip. Darkened color of textarea's placeholder. Bumped v1 version string. --- controllers/albumsController.js | 14 +++++---- controllers/utilsController.js | 52 +++++++++++++++++++++++++++++++++ database/db.js | 1 + database/migration.js | 9 +++--- public/css/album.css | 6 ++++ public/css/style.css | 12 +++++--- public/js/album.js | 1 + public/js/dashboard.js | 21 ++++++++++--- public/js/home.js | 9 ++++-- routes/album.js | 1 + views/_globals.njk | 2 +- views/album.njk | 18 +++++------- 12 files changed, 115 insertions(+), 31 deletions(-) diff --git a/controllers/albumsController.js b/controllers/albumsController.js index 2a83b01..397bb48 100644 --- a/controllers/albumsController.js +++ b/controllers/albumsController.js @@ -32,7 +32,7 @@ albumsController.list = async (req, res, next) => { let fields = ['id', 'name'] if (req.params.sidebar === undefined) { - fields = fields.concat(fields, ['timestamp', 'identifier', 'editedAt', 'download', 'public']) + fields = fields.concat(fields, ['timestamp', 'identifier', 'editedAt', 'download', 'public', 'description']) } const albums = await db.table('albums') @@ -70,7 +70,7 @@ albumsController.create = async (req, res, next) => { const user = await utils.authorize(req, res) if (!user) { return } - const name = req.body.name + const name = utils.escape(req.body.name) if (name === undefined || name === '') { return res.json({ success: false, description: 'No album name specified.' }) } @@ -102,7 +102,8 @@ albumsController.create = async (req, res, next) => { editedAt: 0, zipGeneratedAt: 0, download: (req.body.download === false || req.body.download === 0) ? 0 : 1, - public: (req.body.public === false || req.body.public === 0) ? 0 : 1 + public: (req.body.public === false || req.body.public === 0) ? 0 : 1, + description: utils.escape(req.body.description) || '' }) return res.json({ success: true, id: ids[0] }) @@ -191,14 +192,14 @@ albumsController.edit = async (req, res, next) => { return res.json({ success: false, description: 'No album specified.' }) } - const name = req.body.name + const name = utils.escape(req.body.name) if (name === undefined || name === '') { return res.json({ success: false, description: 'No name specified.' }) } const album = await db.table('albums') .where({ - name, + id, userid: user.id, enabled: 1 }) @@ -221,7 +222,8 @@ albumsController.edit = async (req, res, next) => { .update({ name, download: Boolean(req.body.download), - public: Boolean(req.body.public) + public: Boolean(req.body.public), + description: utils.escape(req.body.description) || '' }) if (req.body.requestLink) { diff --git a/controllers/utilsController.js b/controllers/utilsController.js index 6fd02d5..efa05e7 100644 --- a/controllers/utilsController.js +++ b/controllers/utilsController.js @@ -54,6 +54,58 @@ utilsController.extname = filename => { return extname + multi } +utilsController.escape = string => { + // MIT License + // Copyright(c) 2012-2013 TJ Holowaychuk + // Copyright(c) 2015 Andreas Lubbe + // Copyright(c) 2015 Tiancheng "Timothy" Gu + + if (!string) { return string } + + const str = '' + string + const match = /["'&<>]/.exec(str) + + if (!match) { return str } + + let escape + let html = '' + let index = 0 + let lastIndex = 0 + + for (index = match.index; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: // " + escape = '"' + break + case 38: // & + escape = '&' + break + case 39: // ' + escape = ''' + break + case 60: // < + escape = '<' + break + case 62: // > + escape = '>' + break + default: + continue + } + + if (lastIndex !== index) { + html += str.substring(lastIndex, index) + } + + lastIndex = index + 1 + html += escape + } + + return lastIndex !== index + ? html + str.substring(lastIndex, index) + : html +} + utilsController.authorize = async (req, res) => { const token = req.headers.token if (token === undefined) { diff --git a/database/db.js b/database/db.js index 656789b..ef24fc2 100644 --- a/database/db.js +++ b/database/db.js @@ -15,6 +15,7 @@ const init = function (db) { table.integer('zipGeneratedAt') table.integer('download') table.integer('public') + table.string('description') }).then(() => {}) } }) diff --git a/database/migration.js b/database/migration.js index 368197c..3ed13d0 100644 --- a/database/migration.js +++ b/database/migration.js @@ -7,7 +7,8 @@ const map = { editedAt: 'integer', zipGeneratedAt: 'integer', download: 'integer', - public: 'integer' + public: 'integer', + description: 'string' }, users: { enabled: 'integer', @@ -23,11 +24,11 @@ migration.start = async () => { const columns = Object.keys(map[table]) return Promise.all(columns.map(async column => { if (await db.schema.hasColumn(table, column)) { - return console.log(`Column "${column}" already exists in table "${table}".`) + return // console.log(`SKIP: ${column} => ${table}.`) } const columnType = map[table][column] return db.schema.table(table, t => { t[columnType](column) }) - .then(() => console.log(`Added column "${column}" to table "${table}".`)) + .then(() => console.log(`OK: ${column} (${columnType}) => ${table}.`)) .catch(console.error) })) })) @@ -45,7 +46,7 @@ migration.start = async () => { console.log(`Updated root's permission to ${perms.permissions.superadmin} (superadmin).`) }) - console.log('Migration finished! Now start lolisafe normally') + console.log('Migration finished! Now you may start lolisafe normally.') process.exit(0) } diff --git a/public/css/album.css b/public/css/album.css index be3f18b..bfd8096 100644 --- a/public/css/album.css +++ b/public/css/album.css @@ -13,6 +13,12 @@ box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2); } +@media screen and (max-width: 768px) { + .description { + text-align: center; + } +} + /* This is the same sheets used in dashboard.css, minus the on-hover ones. I should probably put this in a file named _thumbs.css, remove the ones in dashboard.css, diff --git a/public/css/style.css b/public/css/style.css index 78513dd..1b558ff 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -57,19 +57,23 @@ hr { color: #7f8c8d; } -.input::-moz-placeholder { +.input::-moz-placeholder, +.textarea::-moz-placeholder { color: #7f8c8d; } -.input::-webkit-input-placeholder { +.input::-webkit-input-placeholder, +.textarea::-webkit-input-placeholder { color: #7f8c8d; } -.input:-moz-placeholder { +.input:-moz-placeholder, +.textarea:-moz-placeholder { color: #7f8c8d; } -.input:-ms-input-placeholder { +.input:-ms-input-placeholder, +.textarea:-ms-input-placeholder { color: #7f8c8d; } diff --git a/public/js/album.js b/public/js/album.js index 8146e9c..d77af95 100644 --- a/public/js/album.js +++ b/public/js/album.js @@ -10,6 +10,7 @@ const page = { page.getPrettyBytes = num => { // MIT License // Copyright (c) Sindre Sorhus (sindresorhus.com) + if (!Number.isFinite(num)) { return num } const neg = num < 0 diff --git a/public/js/dashboard.js b/public/js/dashboard.js index b9425c2..bb066de 100644 --- a/public/js/dashboard.js +++ b/public/js/dashboard.js @@ -1046,6 +1046,11 @@ page.getAlbums = function () { +
+
+ +
+
@@ -1090,7 +1095,8 @@ page.getAlbums = function () { page.cache.albums[album.id] = { name: album.name, download: album.download, - public: album.public + public: album.public, + description: album.description } const tr = document.createElement('tr') @@ -1139,9 +1145,13 @@ page.editAlbum = function (id) { const div = document.createElement('div') div.innerHTML = `
-
- + +
+
+
+
+
@@ -1186,6 +1196,7 @@ page.editAlbum = function (id) { axios.post('api/albums/edit', { id, name: document.getElementById('swalName').value, + description: document.getElementById('swalDescription').value, download: document.getElementById('swalDownload').checked, public: document.getElementById('swalPublic').checked, requestLink: document.getElementById('swalRequestLink').checked @@ -1265,7 +1276,8 @@ page.submitAlbum = function (element) { page.isLoading(element, true) axios.post('api/albums', { - name: document.getElementById('albumName').value + name: document.getElementById('albumName').value, + description: document.getElementById('albumDescription').value }).then(function (response) { if (!response) { return } @@ -1572,6 +1584,7 @@ page.getPrettyDate = date => { page.getPrettyBytes = num => { // MIT License // Copyright (c) Sindre Sorhus (sindresorhus.com) + if (!Number.isFinite(num)) { return num } const neg = num < 0 diff --git a/public/js/home.js b/public/js/home.js index be557af..5df9f23 100644 --- a/public/js/home.js +++ b/public/js/home.js @@ -384,9 +384,13 @@ page.createAlbum = function () { const div = document.createElement('div') div.innerHTML = `
-
- + +
+
+
+
+
@@ -423,6 +427,7 @@ page.createAlbum = function () { const name = document.getElementById('swalName').value axios.post('api/albums', { name, + description: document.getElementById('swalDescription').value, download: document.getElementById('swalDownload').checked, public: document.getElementById('swalPublic').checked }, { diff --git a/routes/album.js b/routes/album.js index 77c8e1a..bf0e615 100644 --- a/routes/album.js +++ b/routes/album.js @@ -57,6 +57,7 @@ routes.get('/a/:identifier', async (req, res, next) => { return res.render('album', { title: album.name, + description: album.description.replace(/\n/g, '
'), count: files.length, thumb, files, diff --git a/views/_globals.njk b/views/_globals.njk index fc210e1..a21817b 100644 --- a/views/_globals.njk +++ b/views/_globals.njk @@ -15,7 +15,7 @@ v2: Images and config files (manifest.json, browserconfig.xml, etc). v3: CSS and JS files (libs such as bulma, lazyload, etc). #} -{% set v1 = "0mdbHpy0x2" %} +{% set v1 = "9cK64TLE3Z" %} {% set v2 = "Ii3JYKIhb0" %} {% set v3 = "ll7yHY3b2b" %} diff --git a/views/album.njk b/views/album.njk index 1586553..843bd4b 100644 --- a/views/album.njk +++ b/views/album.njk @@ -16,7 +16,7 @@ {% block opengraph %} - + @@ -24,7 +24,7 @@ - + {% endblock %} @@ -37,7 +37,7 @@

- {{ title }} + {{ title | safe }}

@@ -51,7 +51,7 @@

{% if downloadLink -%} - Download album + Download album {%- else -%} Download disabled {%- endif %} @@ -59,12 +59,10 @@

{%- endif %} - {% if generateZips and downloadLink and files.length -%} -
-
- Album archives may be cached by CDN, if the one you have downloaded seems outdated, refresh the page to get the latest download link. -
-
+ {% if description -%} +

+ {{ description | safe }} +

{%- endif %}
{% if files.length -%}