mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2024-12-12 23:46:22 +00:00
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.
This commit is contained in:
parent
42b6c74711
commit
da86f605c6
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -15,6 +15,7 @@ const init = function (db) {
|
||||
table.integer('zipGeneratedAt')
|
||||
table.integer('download')
|
||||
table.integer('public')
|
||||
table.string('description')
|
||||
}).then(() => {})
|
||||
}
|
||||
})
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ const page = {
|
||||
page.getPrettyBytes = num => {
|
||||
// MIT License
|
||||
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
|
||||
if (!Number.isFinite(num)) { return num }
|
||||
|
||||
const neg = num < 0
|
||||
|
@ -1046,6 +1046,11 @@ page.getAlbums = function () {
|
||||
<input id="albumName" class="input" type="text" placeholder="Name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<textarea id="albumDescription" class="textarea" placeholder="Description" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<a id="submitAlbum" class="button is-breeze is-fullwidth" data-action="submit-album">
|
||||
@ -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 = `
|
||||
<div class="field">
|
||||
<label class="label">Album name</label>
|
||||
<div class="controls">
|
||||
<input id="swalName" class="input" type="text" value="${album.name || ''}">
|
||||
<input id="swalName" class="input" type="text" placeholder="Name" value="${album.name || ''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<textarea id="swalDescription" class="textarea" placeholder="Description" rows="2">${album.description || ''}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
@ -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@gmail.com> (sindresorhus.com)
|
||||
|
||||
if (!Number.isFinite(num)) { return num }
|
||||
|
||||
const neg = num < 0
|
||||
|
@ -384,9 +384,13 @@ page.createAlbum = function () {
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = `
|
||||
<div class="field">
|
||||
<label class="label">Album name</label>
|
||||
<div class="controls">
|
||||
<input id="swalName" class="input" type="text" placeholder="My super album">
|
||||
<input id="swalName" class="input" type="text" placeholder="Name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<textarea id="swalDescription" class="textarea" placeholder="Description" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
@ -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
|
||||
}, {
|
||||
|
@ -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, '<br>'),
|
||||
count: files.length,
|
||||
thumb,
|
||||
files,
|
||||
|
@ -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" %}
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
{% block opengraph %}
|
||||
<!-- Open Graph tags -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="{{ title }} – {{ count }} files" />
|
||||
<meta property="og:title" content="{{ title | safe }} – {{ count }} files" />
|
||||
<meta property="og:url" content="{{ url }}" />
|
||||
<meta property="og:description" content="A pomf-like file uploading service that doesn't suck." />
|
||||
<meta property="og:image" content="{{ thumb }}" />
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
<!-- Twitter Card tags -->
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="{{ title }} – {{ count }} files">
|
||||
<meta name="twitter:title" content="{{ title | safe }} – {{ count }} files">
|
||||
<meta name="twitter:description" content="A pomf-like file uploading service that doesn't suck.">
|
||||
<meta name="twitter:image" content="{{ thumb }}">
|
||||
{% endblock %}
|
||||
@ -37,7 +37,7 @@
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h1 id="title" class="title">
|
||||
{{ title }}
|
||||
{{ title | safe }}
|
||||
</h1>
|
||||
</div>
|
||||
<div class="level-item">
|
||||
@ -51,7 +51,7 @@
|
||||
<div class="level-right">
|
||||
<p class="level-item">
|
||||
{% if downloadLink -%}
|
||||
<a class="button is-primary is-outlined" title="Download album" href="{{ downloadLink }}">Download album</a>
|
||||
<a class="button is-primary is-outlined" title="Be aware that album archive may be cached by CDN" href="{{ downloadLink }}">Download album</a>
|
||||
{%- else -%}
|
||||
<a class="button is-primary is-outlined" title="The album's owner has chosen to disable download" disabled>Download disabled</a>
|
||||
{%- endif %}
|
||||
@ -59,12 +59,10 @@
|
||||
</div>
|
||||
{%- endif %}
|
||||
</nav>
|
||||
{% if generateZips and downloadLink and files.length -%}
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Album archives may be cached by CDN, if the one you have downloaded seems outdated, refresh the page to get the latest download link.
|
||||
</div>
|
||||
</article>
|
||||
{% if description -%}
|
||||
<h2 class="subtitle description">
|
||||
{{ description | safe }}
|
||||
</h2>
|
||||
{%- endif %}
|
||||
<hr>
|
||||
{% if files.length -%}
|
||||
|
Loading…
Reference in New Issue
Block a user