mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2025-01-18 17:21:33 +00:00
Updates
* Refactored all instances of "err" into "error". * Added bulk delete feature (API route: /api/uploads/bulkdelete). It accepts an array of IDs (its key must be "ids" in the JSON POST request). Don't forget it still requires a token in the headers. (https://s.fiery.me/6rjMAYoC.mp4) * Removed fontello.css from auth.html. * Updated a bunch of styling. * Added "copy link to clipboard" button to thumbs view. * Added "view thumbnail" button to list view. Clicking the row will no longer trigger thumb view, instead you have to press that button. * Updated icons. * ... and perhaps some others that I can't remember?
This commit is contained in:
parent
d2086ce4ba
commit
0067c8fe83
@ -161,8 +161,8 @@ albumsController.generateZip = async (req, res, next) => {
|
||||
try {
|
||||
// const exists = fs.statSync(path.join(__dirname, '..', config.uploads.folder, file.name))
|
||||
archive.file(file.name, fs.readFileSync(path.join(__dirname, '..', config.uploads.folder, file.name)))
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,9 @@ authController.verify = async (req, res, next) => {
|
||||
})
|
||||
}
|
||||
|
||||
bcrypt.compare(password, user.password, (err, result) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
bcrypt.compare(password, user.password, (error, result) => {
|
||||
if (error) {
|
||||
console.log(error)
|
||||
return res.json({ success: false, description: 'There was an error.' })
|
||||
}
|
||||
if (result === false) { return res.json({ success: false, description: 'Wrong password.' }) }
|
||||
@ -53,9 +53,9 @@ authController.register = async (req, res, next) => {
|
||||
const user = await db.table('users').where('username', username).first()
|
||||
if (user) { return res.json({ success: false, description: 'Username already exists.' }) }
|
||||
|
||||
bcrypt.hash(password, 10, async (err, hash) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
bcrypt.hash(password, 10, async (error, hash) => {
|
||||
if (error) {
|
||||
console.log(error)
|
||||
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻.' })
|
||||
}
|
||||
const token = randomstring.generate(64)
|
||||
@ -80,9 +80,9 @@ authController.changePassword = async (req, res, next) => {
|
||||
return res.json({ success: false, description: 'Password must have 6-64 characters.' })
|
||||
}
|
||||
|
||||
bcrypt.hash(password, 10, async (err, hash) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
bcrypt.hash(password, 10, async (error, hash) => {
|
||||
if (error) {
|
||||
console.log(error)
|
||||
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻.' })
|
||||
}
|
||||
|
||||
|
@ -26,15 +26,15 @@ const storage = multer.diskStorage({
|
||||
|
||||
// Check for the existence of UUID dir in chunks dir
|
||||
const uuidDir = path.join(chunksDir, req.body.uuid)
|
||||
fs.access(uuidDir, err => {
|
||||
fs.access(uuidDir, error => {
|
||||
// If it exists, callback
|
||||
if (!err) { return cb(null, uuidDir) }
|
||||
if (!error) { return cb(null, uuidDir) }
|
||||
// It it doesn't, then make it first
|
||||
fs.mkdir(uuidDir, err => {
|
||||
fs.mkdir(uuidDir, error => {
|
||||
// If there was no error, callback
|
||||
if (!err) { return cb(null, uuidDir) }
|
||||
if (!error) { return cb(null, uuidDir) }
|
||||
// Otherwise, log it
|
||||
console.log(err)
|
||||
console.log(error)
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
return cb('Could not process the chunked upload. Try again?')
|
||||
})
|
||||
@ -112,9 +112,9 @@ uploadsController.getFileNameLength = req => {
|
||||
uploadsController.getUniqueRandomName = (length, extension, cb) => {
|
||||
const access = i => {
|
||||
const name = randomstring.generate(length) + extension
|
||||
fs.access(path.join(uploadDir, name), err => {
|
||||
fs.access(path.join(uploadDir, name), error => {
|
||||
// If a file with the same name does not exist
|
||||
if (err) { return cb(null, name) }
|
||||
if (error) { return cb(null, name) }
|
||||
// If a file with the same name already exists, log to console
|
||||
console.log(`A file named ${name} already exists (${++i}/${maxTries}).`)
|
||||
// If it still haven't reached allowed maximum tries, then try again
|
||||
@ -163,16 +163,16 @@ uploadsController.upload = async (req, res, next) => {
|
||||
}
|
||||
|
||||
uploadsController.actuallyUpload = async (req, res, user, albumid) => {
|
||||
const erred = err => {
|
||||
console.log(err)
|
||||
const erred = error => {
|
||||
console.log(error)
|
||||
res.json({
|
||||
success: false,
|
||||
description: err.toString()
|
||||
description: error.toString()
|
||||
})
|
||||
}
|
||||
|
||||
upload(req, res, async err => {
|
||||
if (err) { return erred(err) }
|
||||
upload(req, res, async error => {
|
||||
if (error) { return erred(error) }
|
||||
|
||||
if (req.files.length === 0) { return erred(new Error('No files.')) }
|
||||
|
||||
@ -238,11 +238,11 @@ uploadsController.finishChunks = async (req, res, next) => {
|
||||
}
|
||||
|
||||
uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
const erred = err => {
|
||||
console.log(err)
|
||||
const erred = error => {
|
||||
console.log(error)
|
||||
res.json({
|
||||
success: false,
|
||||
description: err.toString()
|
||||
description: error.toString()
|
||||
})
|
||||
}
|
||||
|
||||
@ -257,15 +257,15 @@ uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
|
||||
const chunksDirUuid = path.join(chunksDir, uuid)
|
||||
|
||||
fs.readdir(chunksDirUuid, async (err, chunks) => {
|
||||
if (err) { return erred(err) }
|
||||
fs.readdir(chunksDirUuid, async (error, chunks) => {
|
||||
if (error) { return erred(error) }
|
||||
if (count < chunks.length) { return erred(new Error('Chunks count mismatch.')) }
|
||||
|
||||
const extension = path.extname(chunks[0])
|
||||
const length = uploadsController.getFileNameLength(req)
|
||||
|
||||
uploadsController.getUniqueRandomName(length, extension, async (err, name) => {
|
||||
if (err) { return erred(err) }
|
||||
uploadsController.getUniqueRandomName(length, extension, async (error, name) => {
|
||||
if (error) { return erred(error) }
|
||||
|
||||
const destination = path.join(uploadDir, name)
|
||||
const destFileStream = fs.createWriteStream(destination, { flags: 'a' })
|
||||
@ -274,9 +274,9 @@ uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
const appended = await uploadsController.appendToStream(destFileStream, chunksDirUuid, chunks)
|
||||
.catch(erred)
|
||||
|
||||
rimraf(chunksDirUuid, err => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
rimraf(chunksDirUuid, error => {
|
||||
if (error) {
|
||||
console.log(error)
|
||||
}
|
||||
})
|
||||
|
||||
@ -314,10 +314,10 @@ uploadsController.appendToStream = async (destFileStream, chunksDirUuid, chunks)
|
||||
.on('end', () => {
|
||||
append(i + 1)
|
||||
})
|
||||
.on('error', err => {
|
||||
console.log(err)
|
||||
.on('error', error => {
|
||||
console.log(error)
|
||||
destFileStream.end()
|
||||
return reject(err)
|
||||
return reject(error)
|
||||
})
|
||||
.pipe(destFileStream, { end: false })
|
||||
} else {
|
||||
@ -373,7 +373,7 @@ uploadsController.writeFilesToDb = async (req, res, user, albumid, infoMap) => {
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
})
|
||||
} else {
|
||||
uploadsController.deleteFile(info.data.filename).then(() => {}).catch(err => console.log(err))
|
||||
uploadsController.deleteFile(info.data.filename).then(() => {}).catch(error => console.log(error))
|
||||
existingFiles.push(dbFile)
|
||||
}
|
||||
|
||||
@ -452,41 +452,91 @@ uploadsController.delete = async (req, res) => {
|
||||
.first()
|
||||
|
||||
try {
|
||||
await uploadsController.deleteFile(file.name).catch(err => {
|
||||
// ENOENT is missing file, for whatever reason, then just delete from db
|
||||
if (err.code !== 'ENOENT') { throw err }
|
||||
await uploadsController.deleteFile(file.name).catch(error => {
|
||||
// ENOENT is missing file, for whatever reason, then just delete from db anyways
|
||||
if (error.code !== 'ENOENT') { throw error }
|
||||
})
|
||||
await db.table('files').where('id', id).del()
|
||||
if (file.albumid) {
|
||||
await db.table('albums').where('id', file.albumid).update('editedAt', Math.floor(Date.now() / 1000))
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
return res.json({ success: true })
|
||||
}
|
||||
|
||||
uploadsController.bulkDelete = async (req, res) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
const ids = req.body.ids
|
||||
if (ids === undefined || !ids.length) {
|
||||
return res.json({ success: false, description: 'No files specified.' })
|
||||
}
|
||||
|
||||
const files = await db.table('files')
|
||||
.whereIn('id', ids)
|
||||
.where(function () {
|
||||
if (user.username !== 'root') {
|
||||
this.where('userid', user.id)
|
||||
}
|
||||
})
|
||||
|
||||
const failedIds = []
|
||||
|
||||
// First, we delete all the physical files
|
||||
await Promise.all(files.map(file => {
|
||||
return uploadsController.deleteFile(file.name).catch(error => {
|
||||
// ENOENT is missing file, for whatever reason, then just delete from db anyways
|
||||
if (error.code !== 'ENOENT') {
|
||||
console.log(error)
|
||||
failedIds.push(file.id)
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
// Second, we filter out failed IDs
|
||||
const successIds = files.filter(file => !failedIds.includes(file.id))
|
||||
await Promise.all(successIds.map(file => {
|
||||
return db.table('files').where('id', file.id).del()
|
||||
.then(() => {
|
||||
if (file.albumid) {
|
||||
return db.table('albums').where('id', file.albumid).update('editedAt', Math.floor(Date.now() / 1000))
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
failedIds.push(file.id)
|
||||
})
|
||||
}))
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
failedIds
|
||||
})
|
||||
}
|
||||
|
||||
uploadsController.deleteFile = function (file) {
|
||||
const ext = path.extname(file).toLowerCase()
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.stat(path.join(__dirname, '..', config.uploads.folder, file), (err, stats) => {
|
||||
if (err) { return reject(err) }
|
||||
fs.unlink(path.join(__dirname, '..', config.uploads.folder, file), err => {
|
||||
if (err) { return reject(err) }
|
||||
fs.stat(path.join(__dirname, '..', config.uploads.folder, file), (error, stats) => {
|
||||
if (error) { return reject(error) }
|
||||
fs.unlink(path.join(__dirname, '..', config.uploads.folder, file), error => {
|
||||
if (error) { return reject(error) }
|
||||
if (!utils.imageExtensions.includes(ext) && !utils.videoExtensions.includes(ext)) {
|
||||
return resolve()
|
||||
}
|
||||
file = file.substr(0, file.lastIndexOf('.')) + '.png'
|
||||
fs.stat(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), (err, stats) => {
|
||||
if (err) {
|
||||
if (err.code !== 'ENOENT') {
|
||||
console.log(err)
|
||||
fs.stat(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), (error, stats) => {
|
||||
if (error) {
|
||||
if (error.code !== 'ENOENT') {
|
||||
console.log(error)
|
||||
}
|
||||
return resolve()
|
||||
}
|
||||
fs.unlink(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), err => {
|
||||
if (err) { return reject(err) }
|
||||
fs.unlink(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), error => {
|
||||
if (error) { return reject(error) }
|
||||
return resolve()
|
||||
})
|
||||
})
|
||||
|
@ -61,8 +61,8 @@ utilsController.generateThumbs = function (file, basedomain) {
|
||||
if (isImageExt && config.uploads.generateThumbnails.image !== true) { return }
|
||||
|
||||
let thumbname = path.join(__dirname, '..', config.uploads.folder, 'thumbs', file.name.slice(0, -ext.length) + '.png')
|
||||
fs.access(thumbname, err => {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
fs.access(thumbname, error => {
|
||||
if (error && error.code === 'ENOENT') {
|
||||
if (isVideoExt) {
|
||||
ffmpeg(path.join(__dirname, '..', config.uploads.folder, file.name))
|
||||
.thumbnail({
|
||||
|
@ -45,8 +45,8 @@ let init = function (db) {
|
||||
db.table('users').where({username: 'root'}).then((user) => {
|
||||
if (user.length > 0) { return }
|
||||
|
||||
require('bcrypt').hash('root', 10, function (err, hash) {
|
||||
if (err) { console.error('Error generating password hash for root') }
|
||||
require('bcrypt').hash('root', 10, function (error, hash) {
|
||||
if (error) { console.error('Error generating password hash for root') }
|
||||
|
||||
db.table('users').insert({
|
||||
username: 'root',
|
||||
|
@ -3,10 +3,10 @@ const db = require('knex')(config.database)
|
||||
|
||||
const migration = {}
|
||||
migration.start = async () => {
|
||||
await db.schema.table('albums', t => t.dateTime('editedAt')).catch(err => console.warn(err.message))
|
||||
await db.schema.table('albums', t => t.dateTime('zipGeneratedAt')).catch(err => console.warn(err.message))
|
||||
await db.schema.table('users', t => t.dateTime('enabled')).catch(err => console.warn(err.message))
|
||||
await db.schema.table('users', t => t.dateTime('fileLength')).catch(err => console.warn(err.message))
|
||||
await db.schema.table('albums', t => t.dateTime('editedAt')).catch(error => console.warn(error.message))
|
||||
await db.schema.table('albums', t => t.dateTime('zipGeneratedAt')).catch(error => console.warn(error.message))
|
||||
await db.schema.table('users', t => t.dateTime('enabled')).catch(error => console.warn(error.message))
|
||||
await db.schema.table('users', t => t.dateTime('fileLength')).catch(error => console.warn(error.message))
|
||||
console.log('Migration finished! Now start lolisafe normally')
|
||||
process.exit(0)
|
||||
}
|
||||
|
12
lolisafe.js
12
lolisafe.js
@ -63,17 +63,17 @@ for (let page of config.pages) {
|
||||
safe.use((req, res, next) => {
|
||||
res.status(404).sendFile('HTTP404.html', { root: '../HttpErrorPages/dist/' })
|
||||
})
|
||||
safe.use((err, req, res, next) => {
|
||||
console.error(err)
|
||||
safe.use((error, req, res, next) => {
|
||||
console.error(error)
|
||||
res.status(500).sendFile('HTTP505.html', { root: '../HttpErrorPages/dist/' })
|
||||
})
|
||||
|
||||
safe.listen(config.port, () => console.log(`lolisafe started on port ${config.port}`))
|
||||
|
||||
process.on('uncaughtException', err => {
|
||||
console.error(`Uncaught Exception:\n${err.stack}`)
|
||||
process.on('uncaughtException', error => {
|
||||
console.error(`Uncaught Exception:\n${error.stack}`)
|
||||
})
|
||||
|
||||
process.on('unhandledRejection', err => {
|
||||
console.error(`Unhandled Rejection (Promise):\n${err.stack}`)
|
||||
process.on('unhandledRejection', error => {
|
||||
console.error(`Unhandled Rejection (Promise):\n${error.stack}`)
|
||||
})
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
<!-- Stylesheets and scripts -->
|
||||
<link rel="stylesheet" type="text/css" href="libs/bulma/bulma.min.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=vZEyc9zyh6">
|
||||
<script type="text/javascript" src="libs/sweetalert/sweetalert.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="libs/axios/axios.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="js/album.js?v=V2RnA3Mwhh"></script>
|
||||
|
@ -11,11 +11,10 @@
|
||||
|
||||
<!-- Stylesheets and scripts -->
|
||||
<link rel="stylesheet" type="text/css" href="libs/bulma/bulma.min.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="libs/fontello/fontello.css?v=V2RnA3Mwhh">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=vZEyc9zyh6">
|
||||
<script type="text/javascript" src="libs/sweetalert/sweetalert.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="libs/axios/axios.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="js/auth.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="js/auth.js?v=vZEyc9zyh6"></script>
|
||||
|
||||
<!-- Open Graph tags -->
|
||||
<meta property="og:type" content="website" />
|
||||
|
@ -11,13 +11,13 @@
|
||||
|
||||
<!-- Stylesheets and scripts -->
|
||||
<link rel="stylesheet" type="text/css" href="libs/bulma/bulma.min.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="libs/fontello/fontello.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="css/dashboard.css?v=GBG98Tjuxh">
|
||||
<link rel="stylesheet" type="text/css" href="libs/fontello/fontello.css?v=vZEyc9zyh6">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=vZEyc9zyh6">
|
||||
<link rel="stylesheet" type="text/css" href="css/dashboard.css?v=vZEyc9zyh6">
|
||||
<script type="text/javascript" src="libs/sweetalert/sweetalert.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="libs/axios/axios.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="libs/clipboard.js/clipboard.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="js/dashboard.js?v=BN63JuN6My"></script>
|
||||
<script type="text/javascript" src="js/dashboard.js?v=vZEyc9zyh6"></script>
|
||||
|
||||
<!-- Open Graph tags -->
|
||||
<meta property="og:type" content="website" />
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
<!-- Stylesheets and scripts -->
|
||||
<link rel="stylesheet" type="text/css" href="libs/bulma/bulma.min.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=vZEyc9zyh6">
|
||||
|
||||
<!-- Open Graph tags -->
|
||||
<meta property="og:type" content="website" />
|
||||
|
@ -11,8 +11,8 @@
|
||||
|
||||
<!-- Stylesheets and scripts -->
|
||||
<link rel="stylesheet" type="text/css" href="libs/bulma/bulma.min.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="libs/fontello/fontello.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="libs/fontello/fontello.css?v=vZEyc9zyh6">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css?v=vZEyc9zyh6">
|
||||
<script type="text/javascript" src="libs/sweetalert/sweetalert.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="libs/dropzone/dropzone.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="libs/axios/axios.min.js?v=8FbubjpYRC"></script>
|
||||
@ -110,7 +110,7 @@
|
||||
<p class="clipboard-mobile is-hidden-desktop" style="display: none">
|
||||
<a class="button is-info is-outlined clipboard-js" style="display: flex">
|
||||
<span class="icon">
|
||||
<i class="icon-attach"></i>
|
||||
<i class="icon-clipboard"></i>
|
||||
</span>
|
||||
<span>Copy link to clipboard</span>
|
||||
</a>
|
||||
|
@ -3,6 +3,32 @@
|
||||
KDE BREEZE DARK
|
||||
------------------ */
|
||||
|
||||
.button.is-breeze {
|
||||
background-color: #2980b9;
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button.is-breeze.is-hovered,
|
||||
.button.is-breeze:hover {
|
||||
background-color: #3daee9;
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button.is-breeze.is-active,
|
||||
.button.is-breeze:active {
|
||||
background-color: #3daee9;
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button.is-breeze.is-focus,
|
||||
.button.is-breeze:focus {
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: #232629;
|
||||
}
|
||||
@ -25,15 +51,6 @@ html {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.button.is-primary {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.button.is-primary.is-hovered,
|
||||
.button.is-primary:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.pagination a {
|
||||
color: #eff0f1;
|
||||
border-color: #4d4d4d;
|
||||
@ -76,6 +93,7 @@ html {
|
||||
|
||||
.table th {
|
||||
color: #eff0f1;
|
||||
height: 2.25em;
|
||||
}
|
||||
|
||||
.table td,
|
||||
@ -88,7 +106,7 @@ html {
|
||||
}
|
||||
|
||||
section#dashboard .table {
|
||||
font-size: 12px
|
||||
font-size: .75rem;
|
||||
}
|
||||
|
||||
section#dashboard div#table div.column {
|
||||
@ -113,21 +131,29 @@ section#dashboard div#table div.column.image-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
section#dashboard div#table div.column a.button {
|
||||
section#dashboard div#table div.column div.controls {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
top: .75rem;
|
||||
right: .75rem;
|
||||
}
|
||||
|
||||
section#dashboard div#table div.column div.controls a.button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
section#dashboard div#table div.column div.controls a.button:not(:active):not(:hover) {
|
||||
background-color: rgba(49, 54, 59, .75);
|
||||
}
|
||||
|
||||
section#dashboard div#table div.column div.name {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: .75rem;
|
||||
bottom: .75rem;
|
||||
right: .75rem;
|
||||
background-color: rgba(49, 54, 59, .75);
|
||||
color: #eff0f1;
|
||||
padding: 10px;
|
||||
padding: .25rem;
|
||||
font-size: .75rem;
|
||||
}
|
||||
|
||||
@ -135,20 +161,35 @@ section#dashboard div#table div.column div.name span {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
section#dashboard div#table div.column a.button:hover,
|
||||
/*
|
||||
section#dashboard div#table div.column div.controls a.button:hover,
|
||||
section#dashboard div#table div.column a.button:active {
|
||||
background-color: #ff3860;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Make extra info appear on hover only on non-touch devices */
|
||||
|
||||
.no-touch section#dashboard div#table div.column a.button,
|
||||
.no-touch section#dashboard div#table div.column div.controls,
|
||||
.no-touch section#dashboard div#table div.column div.name {
|
||||
opacity: 0;
|
||||
transition: opacity .25s;
|
||||
}
|
||||
|
||||
.no-touch section#dashboard div#table div.column:hover a.button,
|
||||
.no-touch section#dashboard div#table div.column:hover div.controls,
|
||||
.no-touch section#dashboard div#table div.column:hover div.name {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#page {
|
||||
/* fix overflow issue with flex */
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.table-container > table {
|
||||
min-width: 650px;
|
||||
}
|
||||
|
@ -137,10 +137,6 @@ hr {
|
||||
background-color: #898b8d;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#login .input {
|
||||
border-top: 0;
|
||||
border-right: 0;
|
||||
@ -165,15 +161,6 @@ hr {
|
||||
border-color: #2980b9;
|
||||
}
|
||||
|
||||
.button.is-danger {
|
||||
background-color: #da4453;
|
||||
}
|
||||
|
||||
.button.is-danger.is-hovered,
|
||||
.button.is-danger:hover {
|
||||
background-color: #3daee9;
|
||||
}
|
||||
|
||||
.table.is-hoverable tbody tr:not(.is-selected):hover {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ page.do = dest => {
|
||||
localStorage.token = response.data.token
|
||||
window.location = 'dashboard'
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
@ -53,8 +53,8 @@ page.verify = () => {
|
||||
|
||||
window.location = 'dashboard'
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ const panel = {
|
||||
username: undefined,
|
||||
token: localStorage.token,
|
||||
filesView: localStorage.filesView,
|
||||
clipboardJS: undefined
|
||||
clipboardJS: undefined,
|
||||
selectedFiles: []
|
||||
}
|
||||
|
||||
panel.preparePage = () => {
|
||||
@ -45,8 +46,8 @@ panel.verifyToken = (token, reloadOnError) => {
|
||||
panel.username = response.data.username
|
||||
return panel.prepareDashboard()
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
@ -128,20 +129,29 @@ panel.getUploads = (album, page, element) => {
|
||||
<a class="button pagination-next" onclick="panel.getUploads(${album}, ${nextPage}, this)">Next page</a>
|
||||
</nav>
|
||||
`
|
||||
const listType = `
|
||||
const controls = `
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<a class="button is-small is-outlined is-danger" title="List view" onclick="panel.setFilesView('list', ${album}, ${page}, this)">
|
||||
<span class="icon is-small">
|
||||
<i class="icon-th-list"></i>
|
||||
<div class="column"></div>
|
||||
<div class="column" style="text-align: center">
|
||||
<a class="button is-small is-danger" title="List view" onclick="panel.setFilesView('list', ${album}, ${page}, this)">
|
||||
<span class="icon">
|
||||
<i class="icon-th-list-1"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="button is-small is-outlined is-danger" title="Thumbs view" onclick="panel.setFilesView('thumbs', ${album}, ${page}, this)">
|
||||
<span class="icon is-small">
|
||||
<i class="icon-th-large"></i>
|
||||
<a class="button is-small is-danger" title="Thumbs view" onclick="panel.setFilesView('thumbs', ${album}, ${page}, this)">
|
||||
<span class="icon">
|
||||
<i class="icon-th-large-1"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="column" style="text-align: right">
|
||||
<a class="button is-small is-danger" title="Delete selected files" onclick="panel.deleteSelectedFiles()">
|
||||
<span class="icon">
|
||||
<i class="icon-trash"></i>
|
||||
</span>
|
||||
<span class="is-mobile-hidden">Delete selected files</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
@ -149,7 +159,7 @@ panel.getUploads = (album, page, element) => {
|
||||
panel.page.innerHTML = `
|
||||
${pagination}
|
||||
<hr>
|
||||
${listType}
|
||||
${controls}
|
||||
<div class="columns is-multiline is-mobile is-centered" id="table">
|
||||
|
||||
</div>
|
||||
@ -174,11 +184,18 @@ panel.getUploads = (album, page, element) => {
|
||||
div.innerHTML = `<a class="image" href="${item.file}" target="_blank"><h1 class="title">.${item.file.split('.').pop()}</h1></a>`
|
||||
}
|
||||
div.innerHTML += `
|
||||
<a class="button is-small is-danger is-outlined" title="Delete album" onclick="panel.deleteFile(${item.id}, ${album}, ${page})">
|
||||
<span class="icon is-small">
|
||||
<i class="icon-trash-1"></i>
|
||||
</span>
|
||||
</a>
|
||||
<div class="controls">
|
||||
<a class="button is-small is-info clipboard-js" title="Copy link to clipboard" data-clipboard-text="${item.file}">
|
||||
<span class="icon">
|
||||
<i class="icon-clipboard"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="button is-small is-danger" title="Delete file" onclick="panel.deleteFile(${item.id}, ${album}, ${page})">
|
||||
<span class="icon">
|
||||
<i class="icon-trash"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="name">
|
||||
<p><span>${item.name}</span></p>
|
||||
<p>${displayAlbumOrUser ? `<span>${displayAlbumOrUser}</span> – ` : ''}${item.size}</div>
|
||||
@ -192,11 +209,12 @@ panel.getUploads = (album, page, element) => {
|
||||
panel.page.innerHTML = `
|
||||
${pagination}
|
||||
<hr>
|
||||
${listType}
|
||||
${controls}
|
||||
<div class="table-container">
|
||||
<table class="table is-narrow is-fullwidth is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input id="selectAll" type="checkbox" title="Select all files" onclick="panel.selectAllFiles(this)"></th>
|
||||
<th>File</th>
|
||||
<th>${albumOrUser}</th>
|
||||
<th>Size</th>
|
||||
@ -214,7 +232,11 @@ panel.getUploads = (album, page, element) => {
|
||||
|
||||
const table = document.getElementById('table')
|
||||
|
||||
let allFilesSelected = true
|
||||
for (const item of response.data.files) {
|
||||
const selected = panel.selectedFiles.includes(item.id)
|
||||
if (!selected && allFilesSelected) { allFilesSelected = false }
|
||||
|
||||
const tr = document.createElement('tr')
|
||||
|
||||
let displayAlbumOrUser = item.album
|
||||
@ -225,19 +247,25 @@ panel.getUploads = (album, page, element) => {
|
||||
|
||||
tr.innerHTML = `
|
||||
<tr>
|
||||
<th><input type="checkbox" class="file-checkbox" title="Select this file" onclick="panel.selectFile(${item.id}, this)"${selected ? ' checked' : ''}></th>
|
||||
<th><a href="${item.file}" target="_blank">${item.file}</a></th>
|
||||
<th>${displayAlbumOrUser}</th>
|
||||
<td>${item.size}</td>
|
||||
<td>${item.date}</td>
|
||||
<td style="text-align: right">
|
||||
<a class="button is-small is-info is-outlined clipboard-js" title="Copy link to clipboard" data-clipboard-text="${item.file}">
|
||||
<span class="icon is-small">
|
||||
<i class="icon-attach"></i>
|
||||
<a class="button is-small is-primary" title="View thumbnail" onclick="panel.displayThumbnailModal('${item.thumb}')">
|
||||
<span class="icon">
|
||||
<i class="icon-picture-1"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="button is-small is-danger is-outlined" title="Delete album" onclick="panel.deleteFile(${item.id}, ${album}, ${page})">
|
||||
<span class="icon is-small">
|
||||
<i class="icon-trash-1"></i>
|
||||
<a class="button is-small is-info clipboard-js" title="Copy link to clipboard" data-clipboard-text="${item.file}">
|
||||
<span class="icon">
|
||||
<i class="icon-clipboard"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="button is-small is-danger" title="Delete file" onclick="panel.deleteFile(${item.id}, ${album}, ${page})">
|
||||
<span class="icon">
|
||||
<i class="icon-trash"></i>
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
@ -245,22 +273,16 @@ panel.getUploads = (album, page, element) => {
|
||||
`
|
||||
|
||||
table.appendChild(tr)
|
||||
}
|
||||
|
||||
if (item.thumb) {
|
||||
tr.addEventListener('click', function (event) {
|
||||
if (event.target.tagName.toLowerCase() === 'a') { return }
|
||||
if (event.target.className.includes('icon')) { return }
|
||||
document.getElementById('modalImage').src = item.thumb
|
||||
document.getElementById('modal').className += ' is-active'
|
||||
})
|
||||
}
|
||||
if (allFilesSelected && response.data.files.length) {
|
||||
document.getElementById('selectAll').checked = true
|
||||
}
|
||||
}
|
||||
}).catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
|
||||
panel.setFilesView = (view, album, page, element) => {
|
||||
@ -269,6 +291,32 @@ panel.setFilesView = (view, album, page, element) => {
|
||||
panel.getUploads(album, page, element)
|
||||
}
|
||||
|
||||
panel.displayThumbnailModal = thumb => {
|
||||
document.getElementById('modalImage').src = thumb
|
||||
document.getElementById('modal').className += ' is-active'
|
||||
}
|
||||
|
||||
panel.selectAllFiles = element => {
|
||||
const table = document.getElementById('table')
|
||||
const checkboxes = table.getElementsByClassName('file-checkbox')
|
||||
for (const checkbox of checkboxes) {
|
||||
if (checkbox.checked !== element.checked) {
|
||||
checkbox.click()
|
||||
}
|
||||
}
|
||||
element.title = element.checked ? 'Unselect all files' : 'Select all files'
|
||||
}
|
||||
|
||||
panel.selectFile = (id, element) => {
|
||||
if (!panel.selectedFiles.includes(id) && element.checked) {
|
||||
panel.selectedFiles.push(id)
|
||||
localStorage.selectedFiles = JSON.stringify(panel.selectedFiles)
|
||||
} else if (panel.selectedFiles.includes(id) && !element.checked) {
|
||||
panel.selectedFiles.splice(panel.selectedFiles.indexOf(id), 1)
|
||||
localStorage.selectedFiles = JSON.stringify(panel.selectedFiles)
|
||||
}
|
||||
}
|
||||
|
||||
panel.deleteFile = (id, album, page) => {
|
||||
swal({
|
||||
title: 'Are you sure?',
|
||||
@ -299,8 +347,61 @@ panel.deleteFile = (id, album, page) => {
|
||||
swal('Deleted!', 'The file has been deleted.', 'success')
|
||||
panel.getUploads(album, page)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
panel.deleteSelectedFiles = () => {
|
||||
const count = panel.selectedFiles.length
|
||||
if (!count) {
|
||||
return swal('An error occurred', 'You have not selected any files.', 'error')
|
||||
}
|
||||
|
||||
const suffix = `file${count === 1 ? '' : 's'}`
|
||||
swal({
|
||||
title: 'Are you sure?',
|
||||
text: `You won't be able to recover ${count} ${suffix}!`,
|
||||
icon: 'warning',
|
||||
dangerMode: true,
|
||||
buttons: {
|
||||
cancel: true,
|
||||
confirm: {
|
||||
text: `Yes, nuke the ${suffix}!`,
|
||||
closeModal: false
|
||||
}
|
||||
}
|
||||
}).then(value => {
|
||||
if (!value) { return }
|
||||
axios.post('api/upload/bulkdelete', {
|
||||
ids: panel.selectedFiles
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.description === 'No token provided') {
|
||||
return panel.verifyToken(panel.token)
|
||||
} else {
|
||||
return swal('An error occurred', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
let deletedCount = count
|
||||
if (response.data.failedIds && response.data.failedIds.length) {
|
||||
deletedCount -= response.data.failedIds.length
|
||||
panel.selectedFiles = panel.selectedFiles.filter(id => response.data.failedIds.includes(id))
|
||||
} else {
|
||||
panel.selectedFiles = []
|
||||
}
|
||||
|
||||
localStorage.selectedFiles = JSON.stringify(panel.selectedFiles)
|
||||
|
||||
swal('Deleted!', `${deletedCount} file${deletedCount === 1 ? ' has' : 's have'} been deleted.`, 'success')
|
||||
panel.getUploads()
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
})
|
||||
@ -324,14 +425,19 @@ panel.getAlbums = () => {
|
||||
<input id="albumName" class="input" type="text" placeholder="Name">
|
||||
</div>
|
||||
<div class="control">
|
||||
<a id="submitAlbum" class="button is-primary">Submit</a>
|
||||
<a id="submitAlbum" class="button is-breeze">
|
||||
<span class="icon">
|
||||
<i class="icon-paper-plane-empty"></i>
|
||||
</span>
|
||||
<span>Submit</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="subtitle">List of albums</h2>
|
||||
|
||||
<div class="table-container">
|
||||
<table class="table is-narrow is-fullwidth is-hoverable">
|
||||
<table class="table is-fullwidth is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
@ -358,19 +464,19 @@ panel.getAlbums = () => {
|
||||
<td>${item.date}</td>
|
||||
<td><a href="${item.identifier}" target="_blank">${item.identifier}</a></td>
|
||||
<td style="text-align: right">
|
||||
<a class="button is-small is-primary is-outlined" title="Edit name" onclick="panel.renameAlbum(${item.id})">
|
||||
<a class="button is-small is-primary" title="Edit name" onclick="panel.renameAlbum(${item.id})">
|
||||
<span class="icon is-small">
|
||||
<i class="icon-edit"></i>
|
||||
<i class="icon-pencil-1"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="button is-small is-info is-outlined clipboard-js" title="Copy link to clipboard" data-clipboard-text="${item.identifier}">
|
||||
<a class="button is-small is-info clipboard-js" title="Copy link to clipboard" data-clipboard-text="${item.identifier}">
|
||||
<span class="icon is-small">
|
||||
<i class="icon-attach"></i>
|
||||
<i class="icon-clipboard"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="button is-small is-danger is-outlined" title="Delete album" onclick="panel.deleteAlbum(${item.id})">
|
||||
<a class="button is-small is-danger" title="Delete album" onclick="panel.deleteAlbum(${item.id})">
|
||||
<span class="icon is-small">
|
||||
<i class="icon-trash-1"></i>
|
||||
<i class="icon-trash"></i>
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
@ -384,8 +490,8 @@ panel.getAlbums = () => {
|
||||
panel.submitAlbum(this)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
@ -423,8 +529,8 @@ panel.renameAlbum = id => {
|
||||
panel.getAlbumsSidebar()
|
||||
panel.getAlbums()
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
})
|
||||
@ -461,8 +567,8 @@ panel.deleteAlbum = id => {
|
||||
panel.getAlbumsSidebar()
|
||||
panel.getAlbums()
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
})
|
||||
@ -487,8 +593,8 @@ panel.submitAlbum = element => {
|
||||
panel.getAlbumsSidebar()
|
||||
panel.getAlbums()
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
panel.setLoading(element, false)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
@ -524,8 +630,8 @@ panel.getAlbumsSidebar = () => {
|
||||
albumsContainer.appendChild(li)
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
@ -556,7 +662,12 @@ panel.changeFileLength = () => {
|
||||
<input id="fileLength" class="input" type="text" placeholder="Your file length" value="${response.data.fileLength ? Math.min(Math.max(response.data.fileLength, response.data.config.min), response.data.config.max) : response.data.config.default}">
|
||||
</div>
|
||||
<div class="control">
|
||||
<a id="setFileLength" class="button is-primary">Set file name length</a>
|
||||
<a id="setFileLength" class="button is-breeze">
|
||||
<span class="icon">
|
||||
<i class="icon-paper-plane-empty"></i>
|
||||
</span>
|
||||
<span>Set file name length</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help">Default file name length is <b>${response.data.config.default}</b> characters. ${response.data.config.userChangeable ? `Range allowed for user is <b>${response.data.config.min}</b> to <b>${response.data.config.max}</b> characters.` : 'Changing file name length is disabled at the moment.'}</p>
|
||||
@ -567,8 +678,8 @@ panel.changeFileLength = () => {
|
||||
panel.setFileLength(document.getElementById('fileLength').value, this)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
@ -594,8 +705,8 @@ panel.setFileLength = (fileLength, element) => {
|
||||
location.reload()
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
panel.isLoading(element, false)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
@ -622,7 +733,12 @@ panel.changeToken = () => {
|
||||
<input id="token" readonly class="input" type="text" placeholder="Your token" value="${response.data.token}">
|
||||
</div>
|
||||
<div class="control">
|
||||
<a id="getNewToken" class="button is-primary">Request new token</a>
|
||||
<a id="getNewToken" class="button is-breeze">
|
||||
<span class="icon">
|
||||
<i class="icon-arrows-cw"></i>
|
||||
</span>
|
||||
<span>Request new token</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -632,8 +748,8 @@ panel.changeToken = () => {
|
||||
panel.getNewToken(this)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
}
|
||||
@ -660,8 +776,8 @@ panel.getNewToken = element => {
|
||||
location.reload()
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
panel.isLoading(element, false)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
@ -684,7 +800,12 @@ panel.changePassword = () => {
|
||||
<input id="passwordConfirm" class="input is-expanded" type="password" placeholder="Verify your new password">
|
||||
</div>
|
||||
<div class="control">
|
||||
<a id="sendChangePassword" class="button is-primary">Set new password</a>
|
||||
<a id="sendChangePassword" class="button is-breeze">
|
||||
<span class="icon">
|
||||
<i class="icon-paper-plane-empty"></i>
|
||||
</span>
|
||||
<span>Set new password</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -726,8 +847,8 @@ panel.sendNewPassword = (pass, element) => {
|
||||
location.reload()
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
panel.isLoading(element, false)
|
||||
return swal('An error occurred', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
@ -749,6 +870,12 @@ window.onload = () => {
|
||||
document.documentElement.className += ' no-touch'
|
||||
}
|
||||
|
||||
const selectedFiles = localStorage.selectedFiles
|
||||
console.log(selectedFiles)
|
||||
if (selectedFiles) {
|
||||
panel.selectedFiles = JSON.parse(selectedFiles)
|
||||
}
|
||||
|
||||
panel.preparePage()
|
||||
|
||||
panel.clipboardJS = new ClipboardJS('.clipboard-js')
|
||||
|
@ -1,6 +1,15 @@
|
||||
Font license info
|
||||
|
||||
|
||||
## Elusive
|
||||
|
||||
Copyright (C) 2013 by Aristeides Stathopoulos
|
||||
|
||||
Author: Aristeides Stathopoulos
|
||||
License: SIL (http://scripts.sil.org/OFL)
|
||||
Homepage: http://aristeides.com/
|
||||
|
||||
|
||||
## Typicons
|
||||
|
||||
(c) Stephen Hutchings 2012
|
||||
@ -10,3 +19,12 @@ Font license info
|
||||
Homepage: http://typicons.com/
|
||||
|
||||
|
||||
## Font Awesome
|
||||
|
||||
Copyright (C) 2016 by Dave Gandy
|
||||
|
||||
Author: Dave Gandy
|
||||
License: SIL ()
|
||||
Homepage: http://fortawesome.github.com/Font-Awesome/
|
||||
|
||||
|
||||
|
43
public/libs/fontello/fontello.css
vendored
43
public/libs/fontello/fontello.css
vendored
@ -1,11 +1,11 @@
|
||||
@font-face {
|
||||
font-family: 'fontello';
|
||||
src: url('fontello.eot?31646562');
|
||||
src: url('fontello.eot?31646562#iefix') format('embedded-opentype'),
|
||||
url('fontello.woff2?31646562') format('woff2'),
|
||||
url('fontello.woff?31646562') format('woff'),
|
||||
url('fontello.ttf?31646562') format('truetype'),
|
||||
url('fontello.svg?31646562#fontello') format('svg');
|
||||
src: url('fontello.eot?10332206');
|
||||
src: url('fontello.eot?10332206#iefix') format('embedded-opentype'),
|
||||
url('fontello.woff2?10332206') format('woff2'),
|
||||
url('fontello.woff?10332206') format('woff'),
|
||||
url('fontello.ttf?10332206') format('truetype'),
|
||||
url('fontello.svg?10332206#fontello') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@ -28,20 +28,35 @@
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
/* line-height: 1em; */
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
||||
.icon-edit:before { content: '\e800'; } /* '' */
|
||||
.icon-th-list-1:before { content: '\e800'; } /* '' */
|
||||
.icon-upload-cloud:before { content: '\e801'; } /* '' */
|
||||
.icon-trash-1:before { content: '\e802'; } /* '' */
|
||||
.icon-th-list:before { content: '\e803'; } /* '' */
|
||||
.icon-attach:before { content: '\e804'; } /* '' */
|
||||
.icon-th-large:before { content: '\e805'; } /* '' */
|
||||
.icon-picture-1:before { content: '\e802'; } /* '' */
|
||||
.icon-th-large-1:before { content: '\e803'; } /* '' */
|
||||
.icon-trash:before { content: '\e804'; } /* '' */
|
||||
.icon-pencil-1:before { content: '\e805'; } /* '' */
|
||||
.icon-clipboard:before { content: '\e806'; } /* '' */
|
||||
.icon-arrows-cw:before { content: '\e807'; } /* '' */
|
||||
.icon-paper-plane-empty:before { content: '\f1d9'; } /* '' */
|
||||
|
Binary file not shown.
@ -6,17 +6,23 @@
|
||||
<font id="fontello" horiz-adv-x="1000" >
|
||||
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
||||
<missing-glyph horiz-adv-x="1000" />
|
||||
<glyph glyph-name="edit" unicode="" d="M966 671q24-23 24-55t-24-55l-185-185 0-469q0-21-15-36t-37-16l-676 0q-22 0-37 16t-16 36l0 677q0 21 16 37t37 15l468 0 185 185q24 24 55 24t55-24z m-523-486l327 328-112 112-328-327z m-134 69l4-86 88-4z m369-295l0 312-167-160q-20-20-63-33t-80-14l-159 0 0 159q0 41 11 82t31 61l165 167-312 0 0-574 574 0z m130 590l67 67-114 114-67-67z" horiz-adv-x="990" />
|
||||
<glyph glyph-name="th-list-1" unicode="" d="M0-150l0 250 250 0 0-250-250 0z m0 375l0 250 250 0 0-250-250 0z m0 375l0 250 250 0 0-250-250 0z m391-750l0 250 609 0 0-250-609 0z m0 375l0 250 609 0 0-250-609 0z m0 375l0 250 609 0 0-250-609 0z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="upload-cloud" unicode="" d="M781 506q108 0 184-76t76-184-76-184-184-77l-208 0 0 239 67-66q16-17 38-17 20 0 36 17 15 15 15 36t-15 36l-156 156q-14 14-37 15t-37-15l-156-156q-15-15-15-36t15-36q16-17 37-17 20 0 36 17l68 66 0-239-260 0q-86 0-148 61t-61 148q0 72 44 128t112 73l0 8q0 130 92 221t221 91q100 0 180-58t114-152q2 0 8 1t10 0z" horiz-adv-x="1041" />
|
||||
|
||||
<glyph glyph-name="trash-1" unicode="" d="M729 636q21 0 37-15t15-36-15-37-37-15l0-417q0-86-61-147t-147-62l-261 0q-86 0-147 62t-60 147l0 417q-22 0-37 15t-16 37 16 36 37 15l51 0 0 53q0 42 30 73t75 31l364 0q43 0 74-31t31-73l0-53 51 0z m-520 53l0-53 364 0 0 53-364 0z m416-573l0 417-469 0 0-417q0-43 31-74t73-31l261 0q43 0 73 31t31 74z m-390 338q10 0 18-8t7-17l0-313q0-10-7-18t-18-8-18 8-8 18l0 313q0 10 8 17t18 8z m104 0q10 0 18-8t8-17l0-313q0-10-8-18t-18-8-18 8-8 18l0 313q0 10 8 17t18 8z m104 0q10 0 18-8t8-17l0-313q0-10-8-18t-18-8-19 8-8 18l0 313q0 10 8 17t19 8z m105 0q10 0 17-8t8-17l0-313q0-10-8-18t-17-8-19 8-8 18l0 313q0 10 8 17t19 8z" horiz-adv-x="781" />
|
||||
<glyph glyph-name="picture-1" unicode="" d="M0-68l0 836 1000 0 0-836-1000 0z m76 78l848 0 0 680-848 0 0-680z m90 80l0 59 150 195 102-86 193 291 223-228 0-231-668 0z m0 416q0 37 24 62t62 24q33 0 58-24t24-62q0-33-24-57t-58-25q-37 0-62 25t-24 57z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="th-list" unicode="" d="M860 90q43 0 73-31t31-74q0-43-31-73t-73-31l-365 0q-44 0-74 31t-31 73 31 74 74 31l365 0z m0 364q43 0 73-31t31-73-31-73-73-31l-365 0q-44 0-74 31t-31 73 31 73 74 31l365 0z m0 365q43 0 73-31t31-73q0-44-31-74t-73-31l-365 0q-42 0-74 31t-31 74 31 73 74 31l365 0z m-860-834q0 130 130 130t130-130-130-130-130 130z m0 365q0 130 130 130t130-130-130-130-130 130z m0 365q0 130 130 130t130-130-130-130-130 130z" horiz-adv-x="964" />
|
||||
<glyph glyph-name="th-large-1" unicode="" d="M0-150l0 438 438 0 0-438-438 0z m0 563l0 437 438 0 0-437-438 0z m563-563l0 438 437 0 0-438-437 0z m0 563l0 437 437 0 0-437-437 0z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="attach" unicode="" d="M285 223q-52 0-91 38t-39 92q0 55 38 93l236 236q61 61 147 61t148-61 61-148-61-147l-369-369q-61-61-146-61-86 0-148 61t-61 148 61 147l42 41q0-61 37-110l-5-5q-30-30-30-73t30-74 74-30 74 30q61 61 183 184t184 185q30 30 30 73t-30 74q-31 30-74 30t-73-30l-237-236q-7-8-7-19t7-19 19-7 19 7l184 184q31-31 31-74 0-41-31-72l-110-111q-38-38-93-38z" horiz-adv-x="785" />
|
||||
<glyph glyph-name="trash" unicode="" d="M0 633l0 141 289 0 0 76 246 0 0-76 289 0 0-141-824 0z m43-783l0 676 738 0 0-676-738 0z" horiz-adv-x="824" />
|
||||
|
||||
<glyph glyph-name="th-large" unicode="" d="M0 663q0 65 46 110t110 46l104 0q65 0 111-46t45-110l0-104q0-65-45-111t-111-45l-104 0q-65 0-110 45t-46 111l0 104z m521 0q0 65 46 110t111 46l103 0q65 0 111-46t46-110l0-104q0-65-46-111t-111-45l-103 0q-65 0-111 45t-46 111l0 104z m-521-521q0 65 46 110t110 46l104 0q65 0 111-46t45-110l0-104q0-65-45-111t-111-46l-104 0q-65 0-110 46t-46 111l0 104z m521 0q0 65 46 110t111 46l103 0q65 0 111-46t46-110l0-104q0-65-46-111t-111-46l-103 0q-65 0-111 46t-46 111l0 104z" horiz-adv-x="938" />
|
||||
<glyph glyph-name="pencil-1" unicode="" d="M0-143l68 343 274-273z m137 392l422 422 259-260-421-422z m531 494q2 39 31 69t69 31 66-25l131-131q25-26 24-66t-30-69-69-30-66 24l-131 131q-27 27-25 66z" horiz-adv-x="989" />
|
||||
|
||||
<glyph glyph-name="clipboard" unicode="" d="M0-150l0 904 225 0 0-64-161 0 0-774 579 0 0 774-161 0 0 64 225 0 0-904-707 0z m129 129l0 31 31 0 0-31-31 0z m0 121l0 31 31 0 0-31-31 0z m0 121l0 31 31 0 0-31-31 0z m0 121l0 32 31 0 0-32-31 0z m0 121l0 32 31 0 0-32-31 0z m0 96l0 94 129 0 0 97q0 41 27 71t69 29 69-30 28-70q0-56-2-97l129 0 0-94-449 0z m96-582l0 33 353 0 0-33-353 0z m0 121l0 33 353 0 0-33-353 0z m0 121l0 33 353 0 0-33-353 0z m0 121l0 34 353 0 0-34-353 0z m0 121l0 34 353 0 0-34-353 0z m97 260q0-14 9-22t23-9 22 9 9 22-9 24-22 9-23-9-9-24z" horiz-adv-x="707" />
|
||||
|
||||
<glyph glyph-name="arrows-cw" unicode="" d="M0-150l0 402 402 0-160-160q108-107 258-107 125 0 222 75t130 192l138 0q-35-173-173-288t-317-114q-207 0-353 146z m10 598q35 174 173 288t317 114q207 0 354-146l146 146 0-402-402 0 160 160q-108 107-258 107-125 0-222-75t-130-192l-138 0z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="paper-plane-empty" unicode="" d="M984 844q19-13 15-36l-142-857q-3-16-18-25-8-5-18-5-6 0-13 3l-294 120-166-182q-10-12-27-12-7 0-12 2-11 4-17 13t-6 21v252l-264 108q-20 8-22 30-2 22 18 33l928 536q20 12 38-1z m-190-837l123 739-800-462 187-76 482 356-267-444z" horiz-adv-x="1000" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -6,10 +6,14 @@ const utils = require('../controllers/utilsController.js')
|
||||
|
||||
routes.get('/a/:identifier', async (req, res, next) => {
|
||||
let identifier = req.params.identifier
|
||||
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' })
|
||||
if (identifier === undefined) {
|
||||
return res.status(401).json({ success: false, description: 'No identifier provided' })
|
||||
}
|
||||
|
||||
const album = await db.table('albums').where({ identifier, enabled: 1 }).first()
|
||||
if (!album) return res.status(404).sendFile('404.html', { root: './pages/error/' })
|
||||
if (!album) {
|
||||
return res.status(404).sendFile('404.html', { root: './pages/error/' })
|
||||
}
|
||||
|
||||
const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC')
|
||||
let thumb = ''
|
||||
@ -39,7 +43,7 @@ routes.get('/a/:identifier', async (req, res, next) => {
|
||||
}
|
||||
|
||||
let enableDownload = false
|
||||
if (config.uploads.generateZips) enableDownload = true
|
||||
if (config.uploads.generateZips) { enableDownload = true }
|
||||
|
||||
return res.render('album', {
|
||||
layout: false,
|
||||
|
@ -20,6 +20,7 @@ routes.get('/uploads', (req, res, next) => uploadController.list(req, res, next)
|
||||
routes.get('/uploads/:page', (req, res, next) => uploadController.list(req, res, next))
|
||||
routes.post('/upload', (req, res, next) => uploadController.upload(req, res, next))
|
||||
routes.post('/upload/delete', (req, res, next) => uploadController.delete(req, res, next))
|
||||
routes.post('/upload/bulkdelete', (req, res, next) => uploadController.bulkDelete(req, res, next))
|
||||
routes.post('/upload/finishchunks', (req, res, next) => uploadController.finishChunks(req, res, next))
|
||||
routes.post('/upload/:albumid', (req, res, next) => uploadController.upload(req, res, next))
|
||||
routes.get('/album/get/:identifier', (req, res, next) => albumsController.get(req, res, next))
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
<!-- Stylesheets and scripts -->
|
||||
<link rel="stylesheet" type="text/css" href="../libs/bulma/bulma.min.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="../css/style.css?v=8FbubjpYRC">
|
||||
<link rel="stylesheet" type="text/css" href="../css/style.css?v=vZEyc9zyh6">
|
||||
<script type="text/javascript" src="../libs/sweetalert/sweetalert.min.js?v=8FbubjpYRC"></script>
|
||||
<script type="text/javascript" src="../libs/axios/axios.min.js?v=8FbubjpYRC"></script>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user