mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2025-02-20 12:19:03 +00:00
Updated ESLint rule: curly
No more enforced curly for if/else/for/while/do blocks w/ one statement. With that said, auto-fixed all JS files to follow the rule. I'd also like to apologize for the inconveniences this commit cause, after all it was me who intentionally enforced curly rule back then. Why the change of heart? After doing some more non-JS codes recently, I realized it was pretty stupid of me to enforce that.
This commit is contained in:
parent
bca9169ea4
commit
52d336cc45
@ -12,7 +12,7 @@
|
||||
"rules": {
|
||||
"curly": [
|
||||
"error",
|
||||
"all"
|
||||
"multi"
|
||||
],
|
||||
"prefer-const": [
|
||||
"error",
|
||||
|
@ -28,12 +28,11 @@ class ZipEmitter extends EventEmitter {
|
||||
|
||||
albumsController.list = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
let fields = ['id', 'name']
|
||||
if (req.params.sidebar === undefined) {
|
||||
if (req.params.sidebar === undefined)
|
||||
fields = fields.concat(fields, ['timestamp', 'identifier', 'editedAt', 'download', 'public', 'description'])
|
||||
}
|
||||
|
||||
const albums = await db.table('albums')
|
||||
.select(fields)
|
||||
@ -42,9 +41,8 @@ albumsController.list = async (req, res, next) => {
|
||||
userid: user.id
|
||||
})
|
||||
|
||||
if (req.params.sidebar !== undefined) {
|
||||
if (req.params.sidebar !== undefined)
|
||||
return res.json({ success: true, albums })
|
||||
}
|
||||
|
||||
const ids = []
|
||||
for (const album of albums) {
|
||||
@ -59,21 +57,20 @@ albumsController.list = async (req, res, next) => {
|
||||
.select('albumid')
|
||||
const albumsCount = {}
|
||||
|
||||
for (const id of ids) { albumsCount[id] = 0 }
|
||||
for (const file of files) { albumsCount[file.albumid] += 1 }
|
||||
for (const album of albums) { album.files = albumsCount[album.id] }
|
||||
for (const id of ids) albumsCount[id] = 0
|
||||
for (const file of files) albumsCount[file.albumid] += 1
|
||||
for (const album of albums) album.files = albumsCount[album.id]
|
||||
|
||||
return res.json({ success: true, albums, homeDomain })
|
||||
}
|
||||
|
||||
albumsController.create = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const name = utils.escape(req.body.name)
|
||||
if (name === undefined || name === '') {
|
||||
if (name === undefined || name === '')
|
||||
return res.json({ success: false, description: 'No album name specified.' })
|
||||
}
|
||||
|
||||
const album = await db.table('albums')
|
||||
.where({
|
||||
@ -83,15 +80,14 @@ albumsController.create = async (req, res, next) => {
|
||||
})
|
||||
.first()
|
||||
|
||||
if (album) {
|
||||
if (album)
|
||||
return res.json({ success: false, description: 'There\'s already an album with that name.' })
|
||||
}
|
||||
|
||||
const identifier = await albumsController.getUniqueRandomName()
|
||||
.catch(error => {
|
||||
res.json({ success: false, description: error.toString() })
|
||||
})
|
||||
if (!identifier) { return }
|
||||
if (!identifier) return
|
||||
|
||||
const ids = await db.table('albums').insert({
|
||||
name,
|
||||
@ -116,9 +112,9 @@ albumsController.getUniqueRandomName = () => {
|
||||
db.table('albums')
|
||||
.where('identifier', identifier)
|
||||
.then(rows => {
|
||||
if (!rows || !rows.length) { return resolve(identifier) }
|
||||
if (!rows || !rows.length) return resolve(identifier)
|
||||
console.log(`An album with identifier ${identifier} already exists (${++i}/${maxTries}).`)
|
||||
if (i < maxTries) { return select(i) }
|
||||
if (i < maxTries) return select(i)
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
return reject('Sorry, we could not allocate a unique random identifier. Try again?')
|
||||
})
|
||||
@ -130,13 +126,12 @@ albumsController.getUniqueRandomName = () => {
|
||||
|
||||
albumsController.delete = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const id = req.body.id
|
||||
const purge = req.body.purge
|
||||
if (id === undefined || id === '') {
|
||||
if (id === undefined || id === '')
|
||||
return res.json({ success: false, description: 'No album specified.' })
|
||||
}
|
||||
|
||||
let failed = []
|
||||
if (purge) {
|
||||
@ -150,9 +145,8 @@ albumsController.delete = async (req, res, next) => {
|
||||
const ids = files.map(file => file.id)
|
||||
failed = await utils.bulkDeleteFiles('id', ids, user)
|
||||
|
||||
if (failed.length === ids.length) {
|
||||
if (failed.length === ids.length)
|
||||
return res.json({ success: false, description: 'Could not delete any of the files associated with the album.' })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,17 +179,15 @@ albumsController.delete = async (req, res, next) => {
|
||||
|
||||
albumsController.edit = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const id = parseInt(req.body.id)
|
||||
if (isNaN(id)) {
|
||||
if (isNaN(id))
|
||||
return res.json({ success: false, description: 'No album specified.' })
|
||||
}
|
||||
|
||||
const name = utils.escape(req.body.name)
|
||||
if (name === undefined || name === '') {
|
||||
if (name === undefined || name === '')
|
||||
return res.json({ success: false, description: 'No name specified.' })
|
||||
}
|
||||
|
||||
const album = await db.table('albums')
|
||||
.where({
|
||||
@ -205,14 +197,13 @@ albumsController.edit = async (req, res, next) => {
|
||||
})
|
||||
.first()
|
||||
|
||||
if (!album) {
|
||||
if (!album)
|
||||
return res.json({ success: false, description: 'Could not get album with the specified ID.' })
|
||||
} else if (album.id !== id) {
|
||||
else if (album.id !== id)
|
||||
return res.json({ success: false, description: 'Name already in use.' })
|
||||
} else if (req._old && (album.id === id)) {
|
||||
else if (req._old && (album.id === id))
|
||||
// Old rename API
|
||||
return res.json({ success: false, description: 'You did not specify a new name.' })
|
||||
}
|
||||
|
||||
await db.table('albums')
|
||||
.where({
|
||||
@ -240,7 +231,7 @@ albumsController.edit = async (req, res, next) => {
|
||||
.catch(error => {
|
||||
res.json({ success: false, description: error.toString() })
|
||||
})
|
||||
if (!identifier) { return }
|
||||
if (!identifier) return
|
||||
|
||||
await db.table('albums')
|
||||
.where({
|
||||
@ -252,9 +243,9 @@ albumsController.edit = async (req, res, next) => {
|
||||
// Rename zip archive of the album if it exists
|
||||
const zipPath = path.join(zipsDir, `${oldIdentifier}.zip`)
|
||||
return fs.access(zipPath, error => {
|
||||
if (error) { return res.json({ success: true, identifier }) }
|
||||
if (error) return res.json({ success: true, identifier })
|
||||
fs.rename(zipPath, path.join(zipsDir, `${identifier}.zip`), error => {
|
||||
if (!error) { return res.json({ success: true, identifier }) }
|
||||
if (!error) return res.json({ success: true, identifier })
|
||||
console.error(error)
|
||||
res.json({ success: false, description: error.toString() })
|
||||
})
|
||||
@ -271,11 +262,10 @@ albumsController.rename = async (req, res, next) => {
|
||||
}
|
||||
|
||||
albumsController.get = async (req, res, next) => {
|
||||
// TODO: ... what was i supposed to do here?
|
||||
// TODO: Something, can't remember...
|
||||
const identifier = req.params.identifier
|
||||
if (identifier === undefined) {
|
||||
if (identifier === undefined)
|
||||
return res.status(401).json({ success: false, description: 'No identifier provided.' })
|
||||
}
|
||||
|
||||
const album = await db.table('albums')
|
||||
.where({
|
||||
@ -284,14 +274,13 @@ albumsController.get = async (req, res, next) => {
|
||||
})
|
||||
.first()
|
||||
|
||||
if (!album) {
|
||||
if (!album)
|
||||
return res.json({ success: false, description: 'Album not found.' })
|
||||
} else if (album.public === 0) {
|
||||
else if (album.public === 0)
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
description: 'This album is not available for public.'
|
||||
})
|
||||
}
|
||||
|
||||
const title = album.name
|
||||
const files = await db.table('files')
|
||||
@ -303,9 +292,8 @@ albumsController.get = async (req, res, next) => {
|
||||
file.file = `${config.domain}/${file.name}`
|
||||
|
||||
const extname = utils.extname(file.name)
|
||||
if (utils.mayGenerateThumb(extname)) {
|
||||
if (utils.mayGenerateThumb(extname))
|
||||
file.thumb = `${config.domain}/thumbs/${file.name.slice(0, -extname.length)}.png`
|
||||
}
|
||||
}
|
||||
|
||||
return res.json({
|
||||
@ -320,24 +308,22 @@ albumsController.generateZip = async (req, res, next) => {
|
||||
const versionString = parseInt(req.query.v)
|
||||
const download = (filePath, fileName) => {
|
||||
const headers = { 'Access-Control-Allow-Origin': '*' }
|
||||
if (versionString > 0) {
|
||||
if (versionString > 0)
|
||||
// Cache-Control header is useful when using CDN (max-age: 30 days)
|
||||
headers['Cache-Control'] = 'public, max-age=2592000, must-revalidate, proxy-revalidate, immutable, stale-while-revalidate=86400, stale-if-error=604800'
|
||||
}
|
||||
|
||||
return res.download(filePath, fileName, { headers })
|
||||
}
|
||||
|
||||
const identifier = req.params.identifier
|
||||
if (identifier === undefined) {
|
||||
if (identifier === undefined)
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
description: 'No identifier provided.'
|
||||
})
|
||||
}
|
||||
|
||||
if (!config.uploads.generateZips) {
|
||||
if (!config.uploads.generateZips)
|
||||
return res.status(401).json({ success: false, description: 'Zip generation disabled.' })
|
||||
}
|
||||
|
||||
const album = await db.table('albums')
|
||||
.where({
|
||||
@ -346,15 +332,13 @@ albumsController.generateZip = async (req, res, next) => {
|
||||
})
|
||||
.first()
|
||||
|
||||
if (!album) {
|
||||
if (!album)
|
||||
return res.json({ success: false, description: 'Album not found.' })
|
||||
} else if (album.download === 0) {
|
||||
else if (album.download === 0)
|
||||
return res.json({ success: false, description: 'Download for this album is disabled.' })
|
||||
}
|
||||
|
||||
if ((!versionString || versionString <= 0) && album.editedAt) {
|
||||
if ((!versionString || versionString <= 0) && album.editedAt)
|
||||
return res.redirect(`${album.identifier}?v=${album.editedAt}`)
|
||||
}
|
||||
|
||||
if (album.zipGeneratedAt > album.editedAt) {
|
||||
const filePath = path.join(zipsDir, `${identifier}.zip`)
|
||||
@ -368,11 +352,10 @@ albumsController.generateZip = async (req, res, next) => {
|
||||
if (albumsController.zipEmitters.has(identifier)) {
|
||||
console.log(`Waiting previous zip task for album: ${identifier}.`)
|
||||
return albumsController.zipEmitters.get(identifier).once('done', (filePath, fileName, json) => {
|
||||
if (filePath && fileName) {
|
||||
if (filePath && fileName)
|
||||
download(filePath, fileName)
|
||||
} else if (json) {
|
||||
else if (json)
|
||||
res.json(json)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -406,16 +389,15 @@ albumsController.generateZip = async (req, res, next) => {
|
||||
const archive = new Zip()
|
||||
|
||||
let iteration = 0
|
||||
for (const file of files) {
|
||||
for (const file of files)
|
||||
fs.readFile(path.join(uploadsDir, file.name), (error, data) => {
|
||||
if (error) {
|
||||
if (error)
|
||||
console.error(error)
|
||||
} else {
|
||||
else
|
||||
archive.file(file.name, data)
|
||||
}
|
||||
|
||||
iteration++
|
||||
if (iteration === files.length) {
|
||||
if (iteration === files.length)
|
||||
archive
|
||||
.generateNodeStream({
|
||||
type: 'nodebuffer',
|
||||
@ -436,23 +418,20 @@ albumsController.generateZip = async (req, res, next) => {
|
||||
albumsController.zipEmitters.get(identifier).emit('done', filePath, fileName)
|
||||
return download(filePath, fileName)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
albumsController.addFiles = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const ids = req.body.ids
|
||||
if (!ids || !ids.length) {
|
||||
if (!ids || !ids.length)
|
||||
return res.json({ success: false, description: 'No files specified.' })
|
||||
}
|
||||
|
||||
let albumid = req.body.albumid
|
||||
if (typeof albumid !== 'number') { albumid = parseInt(albumid) }
|
||||
if (isNaN(albumid) || (albumid < 0)) { albumid = null }
|
||||
if (typeof albumid !== 'number') albumid = parseInt(albumid)
|
||||
if (isNaN(albumid) || (albumid < 0)) albumid = null
|
||||
|
||||
const albumids = []
|
||||
|
||||
@ -460,15 +439,13 @@ albumsController.addFiles = async (req, res, next) => {
|
||||
const album = await db.table('albums')
|
||||
.where('id', albumid)
|
||||
.where(function () {
|
||||
if (user.username !== 'root') {
|
||||
if (user.username !== 'root')
|
||||
this.where('userid', user.id)
|
||||
}
|
||||
})
|
||||
.first()
|
||||
|
||||
if (!album) {
|
||||
if (!album)
|
||||
return res.json({ success: false, description: 'Album doesn\'t exist or it doesn\'t belong to the user.' })
|
||||
}
|
||||
|
||||
albumids.push(albumid)
|
||||
}
|
||||
@ -476,9 +453,8 @@ albumsController.addFiles = async (req, res, next) => {
|
||||
const files = await db.table('files')
|
||||
.whereIn('id', ids)
|
||||
.where(function () {
|
||||
if (user.username !== 'root') {
|
||||
if (user.username !== 'root')
|
||||
this.where('userid', user.id)
|
||||
}
|
||||
})
|
||||
|
||||
const failed = ids.filter(id => !files.find(file => file.id === id))
|
||||
@ -488,17 +464,15 @@ albumsController.addFiles = async (req, res, next) => {
|
||||
.update('albumid', albumid)
|
||||
.catch(console.error)
|
||||
|
||||
if (!updateDb) {
|
||||
if (!updateDb)
|
||||
return res.json({
|
||||
success: false,
|
||||
description: `Could not ${albumid === null ? 'add' : 'remove'} any files ${albumid === null ? 'to' : 'from'} the album.`
|
||||
})
|
||||
}
|
||||
|
||||
files.forEach(file => {
|
||||
if (file.albumid && !albumids.includes(file.albumid)) {
|
||||
if (file.albumid && !albumids.includes(file.albumid))
|
||||
albumids.push(file.albumid)
|
||||
}
|
||||
})
|
||||
|
||||
await db.table('albums')
|
||||
|
@ -11,47 +11,44 @@ authController.verify = async (req, res, next) => {
|
||||
const username = req.body.username
|
||||
const password = req.body.password
|
||||
|
||||
if (username === undefined) { return res.json({ success: false, description: 'No username provided.' }) }
|
||||
if (password === undefined) { return res.json({ success: false, description: 'No password provided.' }) }
|
||||
if (username === undefined) return res.json({ success: false, description: 'No username provided.' })
|
||||
if (password === undefined) return res.json({ success: false, description: 'No password provided.' })
|
||||
|
||||
const user = await db.table('users').where('username', username).first()
|
||||
if (!user) {
|
||||
if (!user)
|
||||
return res.json({ success: false, description: 'Username doesn\'t exist.' })
|
||||
}
|
||||
if (user.enabled === false || user.enabled === 0) {
|
||||
|
||||
if (user.enabled === false || user.enabled === 0)
|
||||
return res.json({ success: false, description: 'This account has been disabled.' })
|
||||
}
|
||||
|
||||
bcrypt.compare(password, user.password, (error, result) => {
|
||||
if (error) {
|
||||
console.error(error)
|
||||
return res.json({ success: false, description: 'There was an error.' })
|
||||
}
|
||||
if (result === false) { return res.json({ success: false, description: 'Wrong password.' }) }
|
||||
if (result === false) return res.json({ success: false, description: 'Wrong password.' })
|
||||
return res.json({ success: true, token: user.token })
|
||||
})
|
||||
}
|
||||
|
||||
authController.register = async (req, res, next) => {
|
||||
if (config.enableUserAccounts === false) {
|
||||
if (config.enableUserAccounts === false)
|
||||
return res.json({ success: false, description: 'Register is disabled at the moment.' })
|
||||
}
|
||||
|
||||
const username = req.body.username
|
||||
const password = req.body.password
|
||||
|
||||
if (username === undefined) { return res.json({ success: false, description: 'No username provided.' }) }
|
||||
if (password === undefined) { return res.json({ success: false, description: 'No password provided.' }) }
|
||||
if (username === undefined) return res.json({ success: false, description: 'No username provided.' })
|
||||
if (password === undefined) return res.json({ success: false, description: 'No password provided.' })
|
||||
|
||||
if (username.length < 4 || username.length > 32) {
|
||||
if (username.length < 4 || username.length > 32)
|
||||
return res.json({ success: false, description: 'Username must have 4-32 characters.' })
|
||||
}
|
||||
if (password.length < 6 || password.length > 64) {
|
||||
|
||||
if (password.length < 6 || password.length > 64)
|
||||
return res.json({ success: false, description: 'Password must have 6-64 characters.' })
|
||||
}
|
||||
|
||||
const user = await db.table('users').where('username', username).first()
|
||||
if (user) { return res.json({ success: false, description: 'Username already exists.' }) }
|
||||
if (user) return res.json({ success: false, description: 'Username already exists.' })
|
||||
|
||||
bcrypt.hash(password, 10, async (error, hash) => {
|
||||
if (error) {
|
||||
@ -72,14 +69,13 @@ authController.register = async (req, res, next) => {
|
||||
|
||||
authController.changePassword = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const password = req.body.password
|
||||
if (password === undefined) { return res.json({ success: false, description: 'No password provided.' }) }
|
||||
if (password === undefined) return res.json({ success: false, description: 'No password provided.' })
|
||||
|
||||
if (password.length < 6 || password.length > 64) {
|
||||
if (password.length < 6 || password.length > 64)
|
||||
return res.json({ success: false, description: 'Password must have 6-64 characters.' })
|
||||
}
|
||||
|
||||
bcrypt.hash(password, 10, async (error, hash) => {
|
||||
if (error) {
|
||||
@ -97,7 +93,7 @@ authController.changePassword = async (req, res, next) => {
|
||||
|
||||
authController.getFileLengthConfig = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
return res.json({
|
||||
success: true,
|
||||
fileLength: user.fileLength,
|
||||
@ -106,40 +102,36 @@ authController.getFileLengthConfig = async (req, res, next) => {
|
||||
}
|
||||
|
||||
authController.changeFileLength = async (req, res, next) => {
|
||||
if (config.uploads.fileLength.userChangeable === false) {
|
||||
if (config.uploads.fileLength.userChangeable === false)
|
||||
return res.json({
|
||||
success: false,
|
||||
description: 'Changing file name length is disabled at the moment.'
|
||||
})
|
||||
}
|
||||
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const fileLength = parseInt(req.body.fileLength)
|
||||
if (fileLength === undefined) {
|
||||
if (fileLength === undefined)
|
||||
return res.json({
|
||||
success: false,
|
||||
description: 'No file name length provided.'
|
||||
})
|
||||
}
|
||||
if (isNaN(fileLength)) {
|
||||
|
||||
if (isNaN(fileLength))
|
||||
return res.json({
|
||||
success: false,
|
||||
description: 'File name length is not a valid number.'
|
||||
})
|
||||
}
|
||||
|
||||
if (fileLength < config.uploads.fileLength.min || fileLength > config.uploads.fileLength.max) {
|
||||
if (fileLength < config.uploads.fileLength.min || fileLength > config.uploads.fileLength.max)
|
||||
return res.json({
|
||||
success: false,
|
||||
description: `File name length must be ${config.uploads.fileLength.min} to ${config.uploads.fileLength.max} characters.`
|
||||
})
|
||||
}
|
||||
|
||||
if (fileLength === user.fileLength) {
|
||||
if (fileLength === user.fileLength)
|
||||
return res.json({ success: true })
|
||||
}
|
||||
|
||||
await db.table('users')
|
||||
.where('id', user.id)
|
||||
@ -150,32 +142,29 @@ authController.changeFileLength = async (req, res, next) => {
|
||||
|
||||
authController.editUser = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const id = parseInt(req.body.id)
|
||||
if (isNaN(id)) {
|
||||
if (isNaN(id))
|
||||
return res.json({ success: false, description: 'No user specified.' })
|
||||
}
|
||||
|
||||
const target = await db.table('users')
|
||||
.where('id', id)
|
||||
.first()
|
||||
|
||||
if (!target) {
|
||||
if (!target)
|
||||
return res.json({ success: false, description: 'Could not get user with the specified ID.' })
|
||||
} else if (!perms.higher(user, target)) {
|
||||
else if (!perms.higher(user, target))
|
||||
return res.json({ success: false, description: 'The user is in the same or higher group as you.' })
|
||||
} else if (target.username === 'root') {
|
||||
else if (target.username === 'root')
|
||||
return res.json({ success: false, description: 'Root user may not be edited.' })
|
||||
}
|
||||
|
||||
const username = String(req.body.username)
|
||||
if (username.length < 4 || username.length > 32) {
|
||||
if (username.length < 4 || username.length > 32)
|
||||
return res.json({ success: false, description: 'Username must have 4-32 characters.' })
|
||||
}
|
||||
|
||||
let permission = req.body.group ? perms.permissions[req.body.group] : target.permission
|
||||
if (typeof permission !== 'number' || permission < 0) { permission = target.permission }
|
||||
if (typeof permission !== 'number' || permission < 0) permission = target.permission
|
||||
|
||||
await db.table('users')
|
||||
.where('id', id)
|
||||
@ -185,9 +174,8 @@ authController.editUser = async (req, res, next) => {
|
||||
permission
|
||||
})
|
||||
|
||||
if (!req.body.resetPassword) {
|
||||
if (!req.body.resetPassword)
|
||||
return res.json({ success: true, username })
|
||||
}
|
||||
|
||||
const password = randomstring.generate(16)
|
||||
bcrypt.hash(password, 10, async (error, hash) => {
|
||||
@ -206,13 +194,13 @@ authController.editUser = async (req, res, next) => {
|
||||
|
||||
authController.listUsers = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const isadmin = perms.is(user, 'admin')
|
||||
if (!isadmin) { return res.status(403) }
|
||||
if (!isadmin) return res.status(403)
|
||||
|
||||
let offset = req.params.page
|
||||
if (offset === undefined) { offset = 0 }
|
||||
if (offset === undefined) offset = 0
|
||||
|
||||
const users = await db.table('users')
|
||||
// .orderBy('id', 'DESC')
|
||||
@ -220,7 +208,7 @@ authController.listUsers = async (req, res, next) => {
|
||||
.offset(25 * offset)
|
||||
.select('id', 'username', 'enabled', 'fileLength', 'permission')
|
||||
|
||||
if (!users.length) { return res.json({ success: true, users }) }
|
||||
if (!users.length) return res.json({ success: true, users })
|
||||
|
||||
const userids = []
|
||||
|
||||
@ -238,18 +226,18 @@ authController.listUsers = async (req, res, next) => {
|
||||
|
||||
for (const upload of uploads) {
|
||||
// This is the fastest method that I can think of
|
||||
if (maps[upload.userid] === undefined) {
|
||||
if (maps[upload.userid] === undefined)
|
||||
maps[upload.userid] = {
|
||||
count: 0,
|
||||
size: 0
|
||||
}
|
||||
}
|
||||
|
||||
maps[upload.userid].count++
|
||||
maps[upload.userid].size += parseInt(upload.size)
|
||||
}
|
||||
|
||||
for (const user of users) {
|
||||
if (!maps[user.id]) { continue }
|
||||
if (!maps[user.id]) continue
|
||||
user.uploadsCount = maps[user.id].count
|
||||
user.diskUsage = maps[user.id].size
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ permissionController.permissions = {
|
||||
|
||||
permissionController.is = (user, group) => {
|
||||
// root bypass
|
||||
if (user.username === 'root') { return true }
|
||||
if (user.username === 'root') return true
|
||||
const permission = user.permission || 0
|
||||
return permission >= permissionController.permissions[group]
|
||||
}
|
||||
|
@ -8,20 +8,18 @@ const tokenController = {}
|
||||
|
||||
tokenController.verify = async (req, res, next) => {
|
||||
const token = req.body.token
|
||||
if (token === undefined) {
|
||||
if (token === undefined)
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
description: 'No token provided.'
|
||||
})
|
||||
}
|
||||
|
||||
const user = await db.table('users').where('token', token).first()
|
||||
if (!user) {
|
||||
if (!user)
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
description: 'Invalid token.'
|
||||
})
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
@ -32,7 +30,7 @@ tokenController.verify = async (req, res, next) => {
|
||||
|
||||
tokenController.list = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
return res.json({
|
||||
success: true,
|
||||
token: user.token
|
||||
@ -41,7 +39,7 @@ tokenController.list = async (req, res, next) => {
|
||||
|
||||
tokenController.change = async (req, res, next) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const newtoken = randomstring.generate(64)
|
||||
await db.table('users').where('token', user.token).update({
|
||||
|
@ -22,15 +22,14 @@ const urlMaxSizeBytes = parseInt(config.uploads.urlMaxSize) * 1000000
|
||||
const storage = multer.diskStorage({
|
||||
destination (req, file, cb) {
|
||||
// If chunked uploads is disabled or the uploaded file is not a chunk
|
||||
if (!chunkedUploads || (req.body.uuid === undefined && req.body.chunkindex === undefined)) {
|
||||
if (!chunkedUploads || (req.body.uuid === undefined && req.body.chunkindex === undefined))
|
||||
return cb(null, uploadsDir)
|
||||
}
|
||||
|
||||
const uuidDir = path.join(chunksDir, req.body.uuid)
|
||||
fs.access(uuidDir, error => {
|
||||
if (!error) { return cb(null, uuidDir) }
|
||||
if (!error) return cb(null, uuidDir)
|
||||
fs.mkdir(uuidDir, error => {
|
||||
if (!error) { return cb(null, uuidDir) }
|
||||
if (!error) return cb(null, uuidDir)
|
||||
console.error(error)
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
return cb('Could not process the chunked upload. Try again?')
|
||||
@ -62,19 +61,18 @@ const upload = multer({
|
||||
},
|
||||
fileFilter (req, file, cb) {
|
||||
const extname = utils.extname(file.originalname)
|
||||
if (uploadsController.isExtensionFiltered(extname)) {
|
||||
if (uploadsController.isExtensionFiltered(extname))
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
return cb(`${extname ? `${extname.substr(1).toUpperCase()} files` : 'Files with no extension'} are not permitted.`)
|
||||
}
|
||||
|
||||
// Re-map Dropzone keys so people can manually use the API without prepending 'dz'
|
||||
for (const key in req.body) {
|
||||
if (!/^dz/.test(key)) { continue }
|
||||
if (!/^dz/.test(key)) continue
|
||||
req.body[key.replace(/^dz/, '')] = req.body[key]
|
||||
delete req.body[key]
|
||||
}
|
||||
|
||||
if (req.body.chunkindex) {
|
||||
if (req.body.chunkindex)
|
||||
if (chunkedUploads && parseInt(req.body.totalfilesize) > maxSizeBytes) {
|
||||
// This will not be true if "totalfilesize" key does not exist, since "NaN > number" is false.
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
@ -83,29 +81,26 @@ const upload = multer({
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
return cb('Chunked uploads are disabled at the moment.')
|
||||
}
|
||||
}
|
||||
|
||||
return cb(null, true)
|
||||
}
|
||||
}).array('files[]')
|
||||
|
||||
uploadsController.isExtensionFiltered = extname => {
|
||||
if (!extname && config.filterNoExtension) { return true }
|
||||
if (!extname && config.filterNoExtension) return true
|
||||
// If there are extensions that have to be filtered
|
||||
if (extname && config.extensionsFilter && config.extensionsFilter.length) {
|
||||
const match = config.extensionsFilter.some(extension => extname === extension.toLowerCase())
|
||||
if ((config.filterBlacklist && match) || (!config.filterBlacklist && !match)) {
|
||||
if ((config.filterBlacklist && match) || (!config.filterBlacklist && !match))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
uploadsController.getFileNameLength = req => {
|
||||
// If the user has a preferred file length, make sure it is within the allowed range
|
||||
if (req.headers.filelength) {
|
||||
if (req.headers.filelength)
|
||||
return Math.min(Math.max(req.headers.filelength, config.uploads.fileLength.min), config.uploads.fileLength.max)
|
||||
}
|
||||
|
||||
// Let's default it to 32 characters when config key is falsy
|
||||
return config.uploads.fileLength.default || 32
|
||||
@ -119,7 +114,7 @@ uploadsController.getUniqueRandomName = (length, extension, set) => {
|
||||
// Check whether the identifier is already used in cache
|
||||
if (set.has(identifier)) {
|
||||
console.log(`Identifier ${identifier} is already in use (${++i}/${maxTries}).`)
|
||||
if (i < maxTries) { return access(i) }
|
||||
if (i < maxTries) return access(i)
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
return reject('Sorry, we could not allocate a unique random name. Try again?')
|
||||
}
|
||||
@ -131,9 +126,9 @@ uploadsController.getUniqueRandomName = (length, extension, set) => {
|
||||
// can be used by multiple different extensions
|
||||
const name = identifier + extension
|
||||
fs.access(path.join(uploadsDir, name), error => {
|
||||
if (error) { return resolve(name) }
|
||||
if (error) return resolve(name)
|
||||
console.log(`A file named ${name} already exists (${++i}/${maxTries}).`)
|
||||
if (i < maxTries) { return access(i) }
|
||||
if (i < maxTries) return access(i)
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
return reject('Sorry, we could not allocate a unique random name. Try again?')
|
||||
})
|
||||
@ -147,33 +142,29 @@ uploadsController.upload = async (req, res, next) => {
|
||||
let user
|
||||
if (config.private === true) {
|
||||
user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
} else if (req.headers.token) {
|
||||
if (!user) return
|
||||
} else if (req.headers.token)
|
||||
user = await db.table('users').where('token', req.headers.token).first()
|
||||
}
|
||||
|
||||
if (user && (user.enabled === false || user.enabled === 0)) {
|
||||
if (user && (user.enabled === false || user.enabled === 0))
|
||||
return res.json({ success: false, description: 'This account has been disabled.' })
|
||||
}
|
||||
|
||||
if (user && user.fileLength && !req.headers.filelength) {
|
||||
if (user && user.fileLength && !req.headers.filelength)
|
||||
req.headers.filelength = user.fileLength
|
||||
}
|
||||
|
||||
let albumid = parseInt(req.headers.albumid || req.params.albumid)
|
||||
if (isNaN(albumid)) { albumid = null }
|
||||
if (isNaN(albumid)) albumid = null
|
||||
|
||||
if (req.body.urls) {
|
||||
if (req.body.urls)
|
||||
return uploadsController.actuallyUploadByUrl(req, res, user, albumid)
|
||||
} else {
|
||||
else
|
||||
return uploadsController.actuallyUpload(req, res, user, albumid)
|
||||
}
|
||||
}
|
||||
|
||||
uploadsController.actuallyUpload = async (req, res, user, albumid) => {
|
||||
const erred = error => {
|
||||
const isError = error instanceof Error
|
||||
if (isError) { console.error(error) }
|
||||
if (isError) console.error(error)
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
description: isError ? error.toString() : error
|
||||
@ -186,14 +177,14 @@ uploadsController.actuallyUpload = async (req, res, user, albumid) => {
|
||||
'LIMIT_FILE_SIZE',
|
||||
'LIMIT_UNEXPECTED_FILE'
|
||||
]
|
||||
if (expected.includes(error.code)) { return erred(error.toString()) }
|
||||
if (expected.includes(error.code)) return erred(error.toString())
|
||||
return erred(error)
|
||||
}
|
||||
|
||||
if (!req.files || !req.files.length) { return erred('No files.') }
|
||||
if (!req.files || !req.files.length) return erred('No files.')
|
||||
|
||||
// If chunked uploads is enabled and the uploaded file is a chunk, then just say that it was a success
|
||||
if (chunkedUploads && req.body.uuid) { return res.json({ success: true }) }
|
||||
if (chunkedUploads && req.body.uuid) return res.json({ success: true })
|
||||
|
||||
const infoMap = req.files.map(file => {
|
||||
file.albumid = albumid
|
||||
@ -205,12 +196,12 @@ uploadsController.actuallyUpload = async (req, res, user, albumid) => {
|
||||
|
||||
if (config.uploads.scan && config.uploads.scan.enabled) {
|
||||
const scan = await uploadsController.scanFiles(req, infoMap)
|
||||
if (scan) { return erred(scan) }
|
||||
if (scan) return erred(scan)
|
||||
}
|
||||
|
||||
const result = await uploadsController.formatInfoMap(req, res, user, infoMap)
|
||||
.catch(erred)
|
||||
if (!result) { return }
|
||||
if (!result) return
|
||||
|
||||
uploadsController.processFilesForDisplay(req, res, result.files, result.existingFiles)
|
||||
})
|
||||
@ -219,53 +210,48 @@ uploadsController.actuallyUpload = async (req, res, user, albumid) => {
|
||||
uploadsController.actuallyUploadByUrl = async (req, res, user, albumid) => {
|
||||
const erred = error => {
|
||||
const isError = error instanceof Error
|
||||
if (isError) { console.error(error) }
|
||||
if (isError) console.error(error)
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
description: isError ? error.toString() : error
|
||||
})
|
||||
}
|
||||
|
||||
if (!config.uploads.urlMaxSize) { return erred('Upload by URLs is disabled at the moment.') }
|
||||
if (!config.uploads.urlMaxSize) return erred('Upload by URLs is disabled at the moment.')
|
||||
|
||||
const urls = req.body.urls
|
||||
if (!urls || !(urls instanceof Array)) { return erred('Missing "urls" property (Array).') }
|
||||
if (!urls || !(urls instanceof Array)) return erred('Missing "urls" property (Array).')
|
||||
|
||||
// DuckDuckGo's proxy
|
||||
if (config.uploads.urlDuckDuckGoProxy) {
|
||||
if (config.uploads.urlDuckDuckGoProxy)
|
||||
return erred('URL uploads unavailable. Please contact the site owner.')
|
||||
// urls = urls.map(url => `https://proxy.duckduckgo.com/iu/?u=${encodeURIComponent(url)}&f=1`)
|
||||
}
|
||||
|
||||
let iteration = 0
|
||||
const infoMap = []
|
||||
for (const url of urls) {
|
||||
const original = path.basename(url).split(/[?#]/)[0]
|
||||
const extension = utils.extname(original)
|
||||
if (uploadsController.isExtensionFiltered(extension)) {
|
||||
if (uploadsController.isExtensionFiltered(extension))
|
||||
return erred(`${extension.substr(1).toUpperCase()} files are not permitted due to security reasons.`)
|
||||
}
|
||||
|
||||
try {
|
||||
const fetchHead = await fetch(url, { method: 'HEAD' })
|
||||
if (fetchHead.status !== 200) {
|
||||
if (fetchHead.status !== 200)
|
||||
return erred(`${fetchHead.status} ${fetchHead.statusText}`)
|
||||
}
|
||||
|
||||
const headers = fetchHead.headers
|
||||
const size = parseInt(headers.get('content-length'))
|
||||
if (isNaN(size)) {
|
||||
if (isNaN(size))
|
||||
return erred('URLs with missing Content-Length HTTP header are not supported.')
|
||||
}
|
||||
if (size > urlMaxSizeBytes) {
|
||||
|
||||
if (size > urlMaxSizeBytes)
|
||||
return erred('File too large.')
|
||||
}
|
||||
|
||||
// limit max response body size with content-length
|
||||
const fetchFile = await fetch(url, { size })
|
||||
if (fetchFile.status !== 200) {
|
||||
if (fetchFile.status !== 200)
|
||||
return erred(`${fetchHead.status} ${fetchHead.statusText}`)
|
||||
}
|
||||
|
||||
const file = await fetchFile.buffer()
|
||||
|
||||
@ -274,7 +260,7 @@ uploadsController.actuallyUploadByUrl = async (req, res, user, albumid) => {
|
||||
|
||||
const destination = path.join(uploadsDir, name)
|
||||
fs.writeFile(destination, file, async error => {
|
||||
if (error) { return erred(error) }
|
||||
if (error) return erred(error)
|
||||
|
||||
const data = {
|
||||
filename: name,
|
||||
@ -293,12 +279,12 @@ uploadsController.actuallyUploadByUrl = async (req, res, user, albumid) => {
|
||||
if (iteration === urls.length) {
|
||||
if (config.uploads.scan && config.uploads.scan.enabled) {
|
||||
const scan = await uploadsController.scanFiles(req, infoMap)
|
||||
if (scan) { return erred(scan) }
|
||||
if (scan) return erred(scan)
|
||||
}
|
||||
|
||||
const result = await uploadsController.formatInfoMap(req, res, user, infoMap)
|
||||
.catch(erred)
|
||||
if (!result) { return }
|
||||
if (!result) return
|
||||
|
||||
uploadsController.processFilesForDisplay(req, res, result.files, result.existingFiles)
|
||||
}
|
||||
@ -308,28 +294,24 @@ uploadsController.actuallyUploadByUrl = async (req, res, user, albumid) => {
|
||||
}
|
||||
|
||||
uploadsController.finishChunks = async (req, res, next) => {
|
||||
if (!chunkedUploads) {
|
||||
if (!chunkedUploads)
|
||||
return res.json({ success: false, description: 'Chunked upload is disabled at the moment.' })
|
||||
}
|
||||
|
||||
let user
|
||||
if (config.private === true) {
|
||||
user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
} else if (req.headers.token) {
|
||||
if (!user) return
|
||||
} else if (req.headers.token)
|
||||
user = await db.table('users').where('token', req.headers.token).first()
|
||||
}
|
||||
|
||||
if (user && (user.enabled === false || user.enabled === 0)) {
|
||||
if (user && (user.enabled === false || user.enabled === 0))
|
||||
return res.json({ success: false, description: 'This account has been disabled.' })
|
||||
}
|
||||
|
||||
if (user && user.fileLength && !req.headers.filelength) {
|
||||
if (user && user.fileLength && !req.headers.filelength)
|
||||
req.headers.filelength = user.fileLength
|
||||
}
|
||||
|
||||
let albumid = parseInt(req.headers.albumid || req.params.albumid)
|
||||
if (isNaN(albumid)) { albumid = null }
|
||||
if (isNaN(albumid)) albumid = null
|
||||
|
||||
return uploadsController.actuallyFinishChunks(req, res, user, albumid)
|
||||
}
|
||||
@ -337,7 +319,7 @@ uploadsController.finishChunks = async (req, res, next) => {
|
||||
uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
const erred = error => {
|
||||
const isError = error instanceof Error
|
||||
if (isError) { console.error(error) }
|
||||
if (isError) console.error(error)
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
description: isError ? error.toString() : error
|
||||
@ -345,31 +327,30 @@ uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
}
|
||||
|
||||
const files = req.body.files
|
||||
if (!files || !(files instanceof Array) || !files.length) { return erred('Invalid "files" property (Array).') }
|
||||
if (!files || !(files instanceof Array) || !files.length) return erred('Invalid "files" property (Array).')
|
||||
|
||||
let iteration = 0
|
||||
const infoMap = []
|
||||
for (const file of files) {
|
||||
if (!file.uuid || typeof file.uuid !== 'string') { return erred('Invalid "uuid" property (string).') }
|
||||
if (typeof file.count !== 'number' || file.count < 1) { return erred('Invalid "count" property (number).') }
|
||||
if (!file.uuid || typeof file.uuid !== 'string') return erred('Invalid "uuid" property (string).')
|
||||
if (typeof file.count !== 'number' || file.count < 1) return erred('Invalid "count" property (number).')
|
||||
|
||||
const uuidDir = path.join(chunksDir, file.uuid)
|
||||
fs.readdir(uuidDir, async (error, chunkNames) => {
|
||||
if (error) {
|
||||
if (error.code === 'ENOENT') { return erred('UUID is not being used.') }
|
||||
if (error.code === 'ENOENT') return erred('UUID is not being used.')
|
||||
return erred(error)
|
||||
}
|
||||
if (file.count < chunkNames.length) { return erred('Chunks count mismatch.') }
|
||||
if (file.count < chunkNames.length) return erred('Chunks count mismatch.')
|
||||
|
||||
const extension = typeof file.original === 'string' ? utils.extname(file.original) : ''
|
||||
if (uploadsController.isExtensionFiltered(extension)) {
|
||||
if (uploadsController.isExtensionFiltered(extension))
|
||||
return erred(`${extension.substr(1).toUpperCase()} files are not permitted due to security reasons.`)
|
||||
}
|
||||
|
||||
const length = uploadsController.getFileNameLength(req)
|
||||
const name = await uploadsController.getUniqueRandomName(length, extension, req.app.get('uploads-set'))
|
||||
.catch(erred)
|
||||
if (!name) { return }
|
||||
if (!name) return
|
||||
|
||||
const destination = path.join(uploadsDir, name)
|
||||
|
||||
@ -379,12 +360,12 @@ uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
// Get total chunks size
|
||||
const chunksTotalSize = await uploadsController.getTotalSize(uuidDir, chunkNames)
|
||||
.catch(erred)
|
||||
if (typeof chunksTotalSize !== 'number') { return }
|
||||
if (typeof chunksTotalSize !== 'number') return
|
||||
if (chunksTotalSize > maxSizeBytes) {
|
||||
// Delete all chunks and remove chunks dir
|
||||
const chunksCleaned = await uploadsController.cleanUpChunks(uuidDir, chunkNames)
|
||||
.catch(erred)
|
||||
if (!chunksCleaned) { return }
|
||||
if (!chunksCleaned) return
|
||||
return erred(`Total chunks size is bigger than ${maxSize}.`)
|
||||
}
|
||||
|
||||
@ -392,12 +373,12 @@ uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
const destFileStream = fs.createWriteStream(destination, { flags: 'a' })
|
||||
const chunksAppended = await uploadsController.appendToStream(destFileStream, uuidDir, chunkNames)
|
||||
.catch(erred)
|
||||
if (!chunksAppended) { return }
|
||||
if (!chunksAppended) return
|
||||
|
||||
// Delete all chunks and remove chunks dir
|
||||
const chunksCleaned = await uploadsController.cleanUpChunks(uuidDir, chunkNames)
|
||||
.catch(erred)
|
||||
if (!chunksCleaned) { return }
|
||||
if (!chunksCleaned) return
|
||||
|
||||
const data = {
|
||||
filename: name,
|
||||
@ -407,7 +388,7 @@ uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
}
|
||||
|
||||
data.albumid = parseInt(file.albumid)
|
||||
if (isNaN(data.albumid)) { data.albumid = albumid }
|
||||
if (isNaN(data.albumid)) data.albumid = albumid
|
||||
|
||||
infoMap.push({
|
||||
path: destination,
|
||||
@ -418,12 +399,12 @@ uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
if (iteration === files.length) {
|
||||
if (config.uploads.scan && config.uploads.scan.enabled) {
|
||||
const scan = await uploadsController.scanFiles(req, infoMap)
|
||||
if (scan) { return erred(scan) }
|
||||
if (scan) return erred(scan)
|
||||
}
|
||||
|
||||
const result = await uploadsController.formatInfoMap(req, res, user, infoMap)
|
||||
.catch(erred)
|
||||
if (!result) { return }
|
||||
if (!result) return
|
||||
|
||||
uploadsController.processFilesForDisplay(req, res, result.files, result.existingFiles)
|
||||
}
|
||||
@ -435,9 +416,9 @@ uploadsController.getTotalSize = (uuidDir, chunkNames) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let size = 0
|
||||
const stat = i => {
|
||||
if (i === chunkNames.length) { return resolve(size) }
|
||||
if (i === chunkNames.length) return resolve(size)
|
||||
fs.stat(path.join(uuidDir, chunkNames[i]), (error, stats) => {
|
||||
if (error) { return reject(error) }
|
||||
if (error) return reject(error)
|
||||
size += stats.size
|
||||
stat(i + 1)
|
||||
})
|
||||
@ -483,7 +464,7 @@ uploadsController.cleanUpChunks = (uuidDir, chunkNames) => {
|
||||
})
|
||||
})).catch(reject)
|
||||
fs.rmdir(uuidDir, error => {
|
||||
if (error) { return reject(error) }
|
||||
if (error) return reject(error)
|
||||
resolve(true)
|
||||
})
|
||||
})
|
||||
@ -509,11 +490,10 @@ uploadsController.formatInfoMap = (req, res, user, infoMap) => {
|
||||
const fileHash = hash.digest('hex')
|
||||
const dbFile = await db.table('files')
|
||||
.where(function () {
|
||||
if (user === undefined) {
|
||||
if (user === undefined)
|
||||
this.whereNull('userid')
|
||||
} else {
|
||||
else
|
||||
this.where('userid', user.id)
|
||||
}
|
||||
})
|
||||
.where({
|
||||
hash: fileHash,
|
||||
@ -555,9 +535,8 @@ uploadsController.formatInfoMap = (req, res, user, infoMap) => {
|
||||
}
|
||||
|
||||
iteration++
|
||||
if (iteration === infoMap.length) {
|
||||
if (iteration === infoMap.length)
|
||||
resolve({ files, existingFiles })
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -567,7 +546,7 @@ uploadsController.scanFiles = (req, infoMap) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const scanner = req.app.get('clam-scanner')
|
||||
let iteration = 0
|
||||
for (const info of infoMap) {
|
||||
for (const info of infoMap)
|
||||
scanner.scanFile(info.path).then(reply => {
|
||||
if (!reply.includes('OK') || reply.includes('FOUND')) {
|
||||
// eslint-disable-next-line no-control-regex
|
||||
@ -577,13 +556,11 @@ uploadsController.scanFiles = (req, infoMap) => {
|
||||
}
|
||||
|
||||
iteration++
|
||||
if (iteration === infoMap.length) {
|
||||
if (iteration === infoMap.length)
|
||||
resolve(null)
|
||||
}
|
||||
}).catch(reject)
|
||||
}
|
||||
}).then(virus => {
|
||||
if (!virus) { return false }
|
||||
if (!virus) return false
|
||||
// If there is at least one dirty file, then delete all files
|
||||
const set = req.app.get('uploads-set')
|
||||
infoMap.forEach(info => {
|
||||
@ -610,16 +587,13 @@ uploadsController.processFilesForDisplay = async (req, res, files, existingFiles
|
||||
// Insert new files to DB
|
||||
await db.table('files').insert(files)
|
||||
|
||||
for (const file of files) {
|
||||
for (const file of files)
|
||||
responseFiles.push(file)
|
||||
}
|
||||
}
|
||||
|
||||
if (existingFiles.length) {
|
||||
for (const file of existingFiles) {
|
||||
if (existingFiles.length)
|
||||
for (const file of existingFiles)
|
||||
responseFiles.push(file)
|
||||
}
|
||||
}
|
||||
|
||||
// We send response first before generating thumbnails and updating album timestamps
|
||||
res.json({
|
||||
@ -635,73 +609,67 @@ uploadsController.processFilesForDisplay = async (req, res, files, existingFiles
|
||||
|
||||
const albumids = []
|
||||
for (const file of files) {
|
||||
if (file.albumid && !albumids.includes(file.albumid)) {
|
||||
if (file.albumid && !albumids.includes(file.albumid))
|
||||
albumids.push(file.albumid)
|
||||
}
|
||||
if (utils.mayGenerateThumb(utils.extname(file.name))) {
|
||||
|
||||
if (utils.mayGenerateThumb(utils.extname(file.name)))
|
||||
utils.generateThumbs(file.name)
|
||||
}
|
||||
}
|
||||
|
||||
if (albumids.length) {
|
||||
if (albumids.length)
|
||||
await db.table('albums')
|
||||
.whereIn('id', albumids)
|
||||
.update('editedAt', Math.floor(Date.now() / 1000))
|
||||
.catch(console.error)
|
||||
}
|
||||
}
|
||||
|
||||
uploadsController.delete = async (req, res) => {
|
||||
const id = parseInt(req.body.id)
|
||||
req.body.field = 'id'
|
||||
req.body.values = isNaN(id) ? undefined : [id]
|
||||
delete req.body.id
|
||||
if (req.body.id !== undefined) delete req.body.id
|
||||
return uploadsController.bulkDelete(req, res)
|
||||
}
|
||||
|
||||
uploadsController.bulkDelete = async (req, res) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const field = req.body.field || 'id'
|
||||
const values = req.body.values
|
||||
|
||||
if (!values || values.constructor.name !== 'Array' || !values.length) {
|
||||
if (!values || !Array.isArray(values) || !values.length)
|
||||
return res.json({ success: false, description: 'No array of files specified.' })
|
||||
}
|
||||
|
||||
const failed = await utils.bulkDeleteFiles(field, values, user, req.app.get('uploads-set'))
|
||||
if (failed.length < values.length) {
|
||||
if (failed.length < values.length)
|
||||
return res.json({ success: true, failed })
|
||||
}
|
||||
|
||||
return res.json({ success: false, description: 'Could not delete any files.' })
|
||||
}
|
||||
|
||||
uploadsController.list = async (req, res) => {
|
||||
const user = await utils.authorize(req, res)
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
let offset = req.params.page
|
||||
if (offset === undefined) { offset = 0 }
|
||||
if (offset === undefined) offset = 0
|
||||
|
||||
// Headers is string-only, this seem to be the safest and lightest
|
||||
const all = req.headers.all === '1'
|
||||
const ismoderator = perms.is(user, 'moderator')
|
||||
if (all && !ismoderator) { return res.json(403) }
|
||||
if (all && !ismoderator) return res.json(403)
|
||||
|
||||
const files = await db.table('files')
|
||||
.where(function () {
|
||||
if (req.params.id === undefined) {
|
||||
if (req.params.id === undefined)
|
||||
this.where('id', '<>', '')
|
||||
} else {
|
||||
else
|
||||
this.where('albumid', req.params.id)
|
||||
}
|
||||
})
|
||||
.where(function () {
|
||||
if (!all || !ismoderator) {
|
||||
if (!all || !ismoderator)
|
||||
this.where('userid', user.id)
|
||||
}
|
||||
})
|
||||
.orderBy('id', 'DESC')
|
||||
.limit(25)
|
||||
@ -711,9 +679,8 @@ uploadsController.list = async (req, res) => {
|
||||
const albums = await db.table('albums')
|
||||
.where(function () {
|
||||
this.where('enabled', 1)
|
||||
if (!all || !ismoderator) {
|
||||
if (!all || !ismoderator)
|
||||
this.where('userid', user.id)
|
||||
}
|
||||
})
|
||||
|
||||
const basedomain = config.domain
|
||||
@ -723,41 +690,33 @@ uploadsController.list = async (req, res) => {
|
||||
file.file = `${basedomain}/${file.name}`
|
||||
|
||||
file.album = ''
|
||||
if (file.albumid !== undefined) {
|
||||
for (const album of albums) {
|
||||
if (file.albumid === album.id) {
|
||||
if (file.albumid !== undefined)
|
||||
for (const album of albums)
|
||||
if (file.albumid === album.id)
|
||||
file.album = album.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only push usernames if we are a moderator
|
||||
if (all && ismoderator) {
|
||||
if (all && ismoderator)
|
||||
if (file.userid !== undefined && file.userid !== null && file.userid !== '') {
|
||||
userids.push(file.userid)
|
||||
}
|
||||
}
|
||||
|
||||
file.extname = utils.extname(file.name)
|
||||
if (utils.mayGenerateThumb(file.extname)) {
|
||||
if (utils.mayGenerateThumb(file.extname))
|
||||
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -file.extname.length)}.png`
|
||||
}
|
||||
}
|
||||
|
||||
// If we are a normal user, send response
|
||||
if (!ismoderator) { return res.json({ success: true, files }) }
|
||||
if (!ismoderator) return res.json({ success: true, files })
|
||||
|
||||
// If we are a moderator but there are no uploads attached to a user, send response
|
||||
if (userids.length === 0) { return res.json({ success: true, files }) }
|
||||
if (userids.length === 0) return res.json({ success: true, files })
|
||||
|
||||
const users = await db.table('users').whereIn('id', userids)
|
||||
for (const dbUser of users) {
|
||||
for (const file of files) {
|
||||
if (file.userid === dbUser.id) {
|
||||
for (const dbUser of users)
|
||||
for (const file of files)
|
||||
if (file.userid === dbUser.id)
|
||||
file.username = dbUser.username
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.json({ success: true, files })
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ utilsController.preserves = ['.tar.gz', '.tar.z', '.tar.bz2', '.tar.lzma', '.tar
|
||||
utilsController.extname = filename => {
|
||||
// Always return blank string if the filename does not seem to have a valid extension
|
||||
// Files such as .DS_Store (anything that starts with a dot, without any extension after) will still be accepted
|
||||
if (!/\../.test(filename)) { return '' }
|
||||
if (!/\../.test(filename)) return ''
|
||||
|
||||
let lower = filename.toLowerCase() // due to this, the returned extname will always be lower case
|
||||
let multi = ''
|
||||
@ -40,16 +40,14 @@ utilsController.extname = filename => {
|
||||
}
|
||||
|
||||
// check against extensions that must be preserved
|
||||
for (let i = 0; i < utilsController.preserves.length; i++) {
|
||||
for (let i = 0; i < utilsController.preserves.length; i++)
|
||||
if (lower.endsWith(utilsController.preserves[i])) {
|
||||
extname = utilsController.preserves[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!extname) {
|
||||
if (!extname)
|
||||
extname = lower.slice(lower.lastIndexOf('.') - lower.length) // path.extname(lower)
|
||||
}
|
||||
|
||||
return extname + multi
|
||||
}
|
||||
@ -60,12 +58,12 @@ utilsController.escape = string => {
|
||||
// Copyright(c) 2015 Andreas Lubbe
|
||||
// Copyright(c) 2015 Tiancheng "Timothy" Gu
|
||||
|
||||
if (!string) { return string }
|
||||
if (!string) return string
|
||||
|
||||
const str = '' + string
|
||||
const match = /["'&<>]/.exec(str)
|
||||
|
||||
if (!match) { return str }
|
||||
if (!match) return str
|
||||
|
||||
let escape
|
||||
let html = ''
|
||||
@ -93,9 +91,8 @@ utilsController.escape = string => {
|
||||
continue
|
||||
}
|
||||
|
||||
if (lastIndex !== index) {
|
||||
if (lastIndex !== index)
|
||||
html += str.substring(lastIndex, index)
|
||||
}
|
||||
|
||||
lastIndex = index + 1
|
||||
html += escape
|
||||
@ -142,15 +139,15 @@ utilsController.generateThumbs = (name, force) => {
|
||||
// Unlink symlink
|
||||
const unlink = await new Promise((resolve, reject) => {
|
||||
fs.unlink(thumbname, error => {
|
||||
if (error) { return reject(error) }
|
||||
if (error) return reject(error)
|
||||
return resolve(true)
|
||||
})
|
||||
}).catch(console.error)
|
||||
if (!unlink) { return resolve(false) }
|
||||
if (!unlink) return resolve(false)
|
||||
}
|
||||
|
||||
// Only make thumbnail if it does not exist (ENOENT)
|
||||
if (!error && !stats.isSymbolicLink() && !force) { return resolve(true) }
|
||||
if (!error && !stats.isSymbolicLink() && !force) return resolve(true)
|
||||
|
||||
// If image extension
|
||||
if (utilsController.imageExtensions.includes(extname)) {
|
||||
@ -169,10 +166,10 @@ utilsController.generateThumbs = (name, force) => {
|
||||
.resize(resizeOptions)
|
||||
.toFile(thumbname)
|
||||
.catch(error => {
|
||||
if (!error) { return resolve(true) }
|
||||
if (!error) return resolve(true)
|
||||
console.error(`${name}: ${error.message.trim()}`)
|
||||
fs.symlink(thumbUnavailable, thumbname, error => {
|
||||
if (error) { console.error(error) }
|
||||
if (error) console.error(error)
|
||||
resolve(!error)
|
||||
})
|
||||
})
|
||||
@ -189,7 +186,7 @@ utilsController.generateThumbs = (name, force) => {
|
||||
.on('error', error => {
|
||||
console.log(`${name}: ${error.message}`)
|
||||
fs.symlink(thumbUnavailable, thumbname, error => {
|
||||
if (error) { console.error(error) }
|
||||
if (error) console.error(error)
|
||||
resolve(!error)
|
||||
})
|
||||
})
|
||||
@ -204,12 +201,12 @@ utilsController.deleteFile = file => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const extname = utilsController.extname(file)
|
||||
return fs.unlink(path.join(uploadsDir, file), error => {
|
||||
if (error && error.code !== 'ENOENT') { return reject(error) }
|
||||
if (error && error.code !== 'ENOENT') return reject(error)
|
||||
|
||||
if (utilsController.imageExtensions.includes(extname) || utilsController.videoExtensions.includes(extname)) {
|
||||
const thumb = file.substr(0, file.lastIndexOf('.')) + '.png'
|
||||
return fs.unlink(path.join(thumbsDir, thumb), error => {
|
||||
if (error && error.code !== 'ENOENT') { return reject(error) }
|
||||
if (error && error.code !== 'ENOENT') return reject(error)
|
||||
resolve(true)
|
||||
})
|
||||
}
|
||||
@ -231,15 +228,14 @@ utilsController.deleteFile = file => {
|
||||
* @return {any[]} failed
|
||||
*/
|
||||
utilsController.bulkDeleteFiles = async (field, values, user, set) => {
|
||||
if (!user || !['id', 'name'].includes(field)) { return }
|
||||
if (!user || !['id', 'name'].includes(field)) return
|
||||
|
||||
const ismoderator = perms.is(user, 'moderator')
|
||||
const files = await db.table('files')
|
||||
.whereIn(field, values)
|
||||
.where(function () {
|
||||
if (!ismoderator) {
|
||||
if (!ismoderator)
|
||||
this.where('userid', user.id)
|
||||
}
|
||||
})
|
||||
|
||||
// an array of file object
|
||||
@ -261,7 +257,7 @@ utilsController.bulkDeleteFiles = async (field, values, user, set) => {
|
||||
})
|
||||
}))
|
||||
|
||||
if (!deletedFiles.length) { return failed }
|
||||
if (!deletedFiles.length) return failed
|
||||
|
||||
// Delete all files from database
|
||||
const deletedIds = deletedFiles.map(file => file.id)
|
||||
@ -269,24 +265,23 @@ utilsController.bulkDeleteFiles = async (field, values, user, set) => {
|
||||
.whereIn('id', deletedIds)
|
||||
.del()
|
||||
.catch(console.error)
|
||||
if (!deleteDb) { return failed }
|
||||
if (!deleteDb) return failed
|
||||
|
||||
if (set) {
|
||||
if (set)
|
||||
deletedFiles.forEach(file => {
|
||||
const identifier = file.name.split('.')[0]
|
||||
set.delete(identifier)
|
||||
// console.log(`Removed ${identifier} from identifiers cache (bulkDeleteFiles)`)
|
||||
})
|
||||
}
|
||||
|
||||
const filtered = files.filter(file => deletedIds.includes(file.id))
|
||||
|
||||
// Update albums if necessary
|
||||
if (deleteDb) {
|
||||
const albumids = []
|
||||
filtered.forEach(file => {
|
||||
if (file.albumid && !albumids.includes(file.albumid)) {
|
||||
if (file.albumid && !albumids.includes(file.albumid))
|
||||
albumids.push(file.albumid)
|
||||
}
|
||||
})
|
||||
await db.table('albums')
|
||||
.whereIn('id', albumids)
|
||||
@ -304,15 +299,15 @@ utilsController.bulkDeleteFiles = async (field, values, user, set) => {
|
||||
}
|
||||
|
||||
utilsController.purgeCloudflareCache = async names => {
|
||||
if (!cloudflareAuth) { return }
|
||||
if (!cloudflareAuth) return
|
||||
|
||||
const thumbs = []
|
||||
names = names.map(name => {
|
||||
const url = `${config.domain}/${name}`
|
||||
const extname = utilsController.extname(name)
|
||||
if (utilsController.mayGenerateThumb(extname)) {
|
||||
if (utilsController.mayGenerateThumb(extname))
|
||||
thumbs.push(`${config.domain}/thumbs/${name.slice(0, -extname.length)}.png`)
|
||||
}
|
||||
|
||||
return url
|
||||
})
|
||||
|
||||
@ -328,9 +323,8 @@ utilsController.purgeCloudflareCache = async names => {
|
||||
}
|
||||
}).then(res => res.json())
|
||||
|
||||
if (fetchPurge.errors) {
|
||||
if (fetchPurge.errors)
|
||||
fetchPurge.errors.forEach(error => console.error(`CF: ${error.code}: ${error.message}`))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`CF: ${error.toString()}`)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
"rules": {
|
||||
"curly": [
|
||||
"error",
|
||||
"all"
|
||||
"multi"
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
|
@ -11,11 +11,11 @@ page.getPrettyBytes = num => {
|
||||
// MIT License
|
||||
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
|
||||
if (!Number.isFinite(num)) { return num }
|
||||
if (!Number.isFinite(num)) return num
|
||||
|
||||
const neg = num < 0
|
||||
if (neg) { num = -num }
|
||||
if (num < 1) { return (neg ? '-' : '') + num + ' B' }
|
||||
if (neg) num = -num
|
||||
if (num < 1) return (neg ? '-' : '') + num + ' B'
|
||||
|
||||
const exponent = Math.min(Math.floor(Math.log10(num) / 3), page.byteUnits.length - 1)
|
||||
const numStr = Number((num / Math.pow(1000, exponent)).toPrecision(3))
|
||||
@ -26,9 +26,8 @@ page.getPrettyBytes = num => {
|
||||
|
||||
window.onload = function () {
|
||||
const elements = document.getElementsByClassName('file-size')
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
for (let i = 0; i < elements.length; i++)
|
||||
elements[i].innerHTML = page.getPrettyBytes(parseInt(elements[i].innerHTML))
|
||||
}
|
||||
|
||||
page.lazyLoad = new LazyLoad()
|
||||
}
|
||||
|
@ -13,21 +13,18 @@ page.do = function (dest) {
|
||||
const user = page.user.value
|
||||
const pass = page.pass.value
|
||||
|
||||
if (!user) {
|
||||
if (!user)
|
||||
return swal('An error occurred!', 'You need to specify a username', 'error')
|
||||
}
|
||||
|
||||
if (!pass) {
|
||||
if (!pass)
|
||||
return swal('An error occurred!', 'You need to specify a username', 'error')
|
||||
}
|
||||
|
||||
axios.post(`api/${dest}`, {
|
||||
username: user,
|
||||
password: pass
|
||||
}).then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
|
||||
localStorage.token = response.data.token
|
||||
window.location = 'dashboard'
|
||||
@ -38,14 +35,13 @@ page.do = function (dest) {
|
||||
}
|
||||
|
||||
page.verify = function () {
|
||||
if (!page.token) { return }
|
||||
if (!page.token) return
|
||||
|
||||
axios.post('api/tokens/verify', {
|
||||
token: page.token
|
||||
}).then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
|
||||
window.location = 'dashboard'
|
||||
}).catch(function (error) {
|
||||
|
@ -83,17 +83,16 @@ page.preparePage = function () {
|
||||
|
||||
page.verifyToken = function (token, reloadOnError) {
|
||||
axios.post('api/tokens/verify', { token }).then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
return swal({
|
||||
title: 'An error occurred!',
|
||||
text: response.data.description,
|
||||
icon: 'error'
|
||||
}).then(function () {
|
||||
if (!reloadOnError) { return }
|
||||
if (!reloadOnError) return
|
||||
localStorage.removeItem(LS_KEYS.token)
|
||||
location.location = 'auth'
|
||||
})
|
||||
}
|
||||
|
||||
axios.defaults.headers.common.token = token
|
||||
localStorage[LS_KEYS.token] = token
|
||||
@ -170,7 +169,7 @@ page.prepareDashboard = function () {
|
||||
|
||||
page.getAlbumsSidebar()
|
||||
|
||||
if (typeof page.prepareShareX === 'function') { page.prepareShareX() }
|
||||
if (typeof page.prepareShareX === 'function') page.prepareShareX()
|
||||
}
|
||||
|
||||
page.logout = function () {
|
||||
@ -182,20 +181,20 @@ page.getItemID = function (element) {
|
||||
// This expects the item's parent to have the item's ID
|
||||
let parent = element.parentNode
|
||||
// If the element is part of a set of controls, use the container's parent instead
|
||||
if (element.parentNode.classList.contains('controls')) { parent = parent.parentNode }
|
||||
if (element.parentNode.classList.contains('controls')) parent = parent.parentNode
|
||||
return parseInt(parent.dataset.id)
|
||||
}
|
||||
|
||||
page.domClick = function (event) {
|
||||
let element = event.target
|
||||
if (!element) { return }
|
||||
if (!element) return
|
||||
|
||||
// If the clicked element is an icon, delegate event to its A parent; hacky
|
||||
if (element.tagName === 'I' && element.parentNode.tagName === 'SPAN') { element = element.parentNode }
|
||||
if (element.tagName === 'SPAN' && element.parentNode.tagName === 'A') { element = element.parentNode }
|
||||
if (element.tagName === 'I' && element.parentNode.tagName === 'SPAN') element = element.parentNode
|
||||
if (element.tagName === 'SPAN' && element.parentNode.tagName === 'A') element = element.parentNode
|
||||
|
||||
// Skip elements that have no action data
|
||||
if (!element.dataset || !element.dataset.action) { return }
|
||||
if (!element.dataset || !element.dataset.action) return
|
||||
|
||||
event.stopPropagation() // maybe necessary
|
||||
const id = page.getItemID(element)
|
||||
@ -210,16 +209,15 @@ page.domClick = function (event) {
|
||||
views.album = page.views.uploads.album
|
||||
views.all = page.views.uploads.all
|
||||
func = page.getUploads
|
||||
} else if (page.currentView === 'users') {
|
||||
} else if (page.currentView === 'users')
|
||||
func = page.getUsers
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case 'page-prev':
|
||||
views.pageNum = page.views[page.currentView].pageNum - 1
|
||||
if (views.pageNum < 0) {
|
||||
if (views.pageNum < 0)
|
||||
return swal('An error occurred!', 'This is already the first page.', 'error')
|
||||
}
|
||||
|
||||
return func(views, element)
|
||||
case 'page-next':
|
||||
views.pageNum = page.views[page.currentView].pageNum + 1
|
||||
@ -264,8 +262,8 @@ page.domClick = function (event) {
|
||||
}
|
||||
|
||||
page.isLoading = function (element, state) {
|
||||
if (!element) { return }
|
||||
if (state) { return element.classList.add('is-loading') }
|
||||
if (!element) return
|
||||
if (state) return element.classList.add('is-loading')
|
||||
element.classList.remove('is-loading')
|
||||
}
|
||||
|
||||
@ -281,32 +279,30 @@ page.fadeIn = function (content) {
|
||||
}
|
||||
|
||||
page.getUploads = function ({ album, pageNum, all } = {}, element) {
|
||||
if (element) { page.isLoading(element, true) }
|
||||
if (pageNum === undefined) { pageNum = 0 }
|
||||
if (element) page.isLoading(element, true)
|
||||
if (pageNum === undefined) pageNum = 0
|
||||
|
||||
let url = `api/uploads/${pageNum}`
|
||||
if (album !== undefined) { url = `api/album/${album}/${pageNum}` }
|
||||
if (album !== undefined) url = `api/album/${album}/${pageNum}`
|
||||
|
||||
if (all && !page.permissions.moderator) {
|
||||
if (all && !page.permissions.moderator)
|
||||
return swal('An error occurred!', 'You can not do this!', 'error')
|
||||
}
|
||||
|
||||
axios.get(url, {
|
||||
headers: {
|
||||
all: all ? '1' : '0'
|
||||
}
|
||||
}).then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
if (pageNum && (response.data.files.length === 0)) {
|
||||
// Only remove loading class here, since beyond this the entire page will be replaced anyways
|
||||
if (element) { page.isLoading(element, false) }
|
||||
if (element) page.isLoading(element, false)
|
||||
return swal('An error occurred!', 'There are no more uploads.', 'error')
|
||||
}
|
||||
|
||||
@ -374,7 +370,7 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
|
||||
for (let i = 0; i < response.data.files.length; i++) {
|
||||
const upload = response.data.files[i]
|
||||
const selected = page.selected.uploads.includes(upload.id)
|
||||
if (!selected && allSelected) { allSelected = false }
|
||||
if (!selected && allSelected) allSelected = false
|
||||
|
||||
page.cache.uploads[upload.id] = {
|
||||
name: upload.name,
|
||||
@ -387,16 +383,15 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
|
||||
upload.prettyDate = page.getPrettyDate(new Date(upload.timestamp * 1000))
|
||||
|
||||
let displayAlbumOrUser = upload.album
|
||||
if (all) { displayAlbumOrUser = upload.username || '' }
|
||||
if (all) displayAlbumOrUser = upload.username || ''
|
||||
|
||||
const div = document.createElement('div')
|
||||
div.className = 'image-container column is-narrow'
|
||||
div.dataset.id = upload.id
|
||||
if (upload.thumb !== undefined) {
|
||||
if (upload.thumb !== undefined)
|
||||
div.innerHTML = `<a class="image" href="${upload.file}" target="_blank" rel="noopener"><img alt="${upload.name}" data-src="${upload.thumb}"/></a>`
|
||||
} else {
|
||||
else
|
||||
div.innerHTML = `<a class="image" href="${upload.file}" target="_blank" rel="noopener"><h1 class="title">${upload.extname || 'N/A'}</h1></a>`
|
||||
}
|
||||
|
||||
div.innerHTML += `
|
||||
<input type="checkbox" class="checkbox" title="Select this file" data-action="select"${selected ? ' checked' : ''}>
|
||||
@ -435,7 +430,7 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
|
||||
}
|
||||
} else {
|
||||
let albumOrUser = 'Album'
|
||||
if (all) { albumOrUser = 'User' }
|
||||
if (all) albumOrUser = 'User'
|
||||
|
||||
page.dom.innerHTML = `
|
||||
${pagination}
|
||||
@ -467,7 +462,7 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
|
||||
for (let i = 0; i < response.data.files.length; i++) {
|
||||
const upload = response.data.files[i]
|
||||
const selected = page.selected.uploads.includes(upload.id)
|
||||
if (!selected && allSelected) { allSelected = false }
|
||||
if (!selected && allSelected) allSelected = false
|
||||
|
||||
page.cache.uploads[upload.id] = {
|
||||
name: upload.name,
|
||||
@ -480,7 +475,7 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
|
||||
upload.prettyDate = page.getPrettyDate(new Date(upload.timestamp * 1000))
|
||||
|
||||
let displayAlbumOrUser = upload.album
|
||||
if (all) { displayAlbumOrUser = upload.username || '' }
|
||||
if (all) displayAlbumOrUser = upload.username || ''
|
||||
|
||||
const tr = document.createElement('tr')
|
||||
tr.dataset.id = upload.id
|
||||
@ -523,14 +518,14 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
|
||||
|
||||
if (allSelected && response.data.files.length) {
|
||||
const selectAll = document.getElementById('selectAll')
|
||||
if (selectAll) { selectAll.checked = true }
|
||||
if (selectAll) selectAll.checked = true
|
||||
}
|
||||
|
||||
page.views.uploads.album = album
|
||||
page.views.uploads.pageNum = response.data.files.length ? pageNum : 0
|
||||
page.views.uploads.all = all
|
||||
}).catch(function (error) {
|
||||
if (element) { page.isLoading(element, false) }
|
||||
if (element) page.isLoading(element, false)
|
||||
console.log(error)
|
||||
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
@ -544,7 +539,7 @@ page.setUploadsView = function (view, element) {
|
||||
|
||||
page.displayThumbnail = function (id) {
|
||||
const file = page.cache.uploads[id]
|
||||
if (!file.thumb) { return }
|
||||
if (!file.thumb) return
|
||||
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = `
|
||||
@ -601,7 +596,7 @@ page.displayThumbnail = function (id) {
|
||||
buttons: false
|
||||
}).then(function () {
|
||||
const video = div.querySelector('#swalVideo')
|
||||
if (video) { video.remove() }
|
||||
if (video) video.remove()
|
||||
|
||||
// Restore modal size
|
||||
document.body.querySelector('.swal-overlay .swal-modal.is-expanded').classList.remove('is-expanded')
|
||||
@ -615,48 +610,45 @@ page.selectAll = function (element) {
|
||||
|
||||
for (let i = 0; i < checkboxes.length; i++) {
|
||||
const id = page.getItemID(checkboxes[i])
|
||||
if (isNaN(id)) { continue }
|
||||
if (isNaN(id)) continue
|
||||
if (checkboxes[i].checked !== element.checked) {
|
||||
checkboxes[i].checked = element.checked
|
||||
if (checkboxes[i].checked) {
|
||||
if (checkboxes[i].checked)
|
||||
selected.push(id)
|
||||
} else {
|
||||
else
|
||||
selected.splice(selected.indexOf(id), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selected.length) {
|
||||
if (selected.length)
|
||||
localStorage[LS_KEYS.selected[currentView]] = JSON.stringify(selected)
|
||||
} else {
|
||||
else
|
||||
localStorage.removeItem(LS_KEYS.selected[currentView])
|
||||
}
|
||||
|
||||
page.selected[currentView] = selected
|
||||
element.title = element.checked ? 'Unselect all uploads' : 'Select all uploads'
|
||||
}
|
||||
|
||||
page.selectInBetween = function (element, lastElement) {
|
||||
if (!element || !lastElement) { return }
|
||||
if (element === lastElement) { return }
|
||||
if (!element || !lastElement) return
|
||||
if (element === lastElement) return
|
||||
|
||||
const currentView = page.currentView
|
||||
const checkboxes = page.checkboxes[currentView]
|
||||
if (!checkboxes || !checkboxes.length) { return }
|
||||
if (!checkboxes || !checkboxes.length) return
|
||||
|
||||
const thisIndex = checkboxes.indexOf(element)
|
||||
const lastIndex = checkboxes.indexOf(lastElement)
|
||||
|
||||
const distance = thisIndex - lastIndex
|
||||
if (distance >= -1 && distance <= 1) { return }
|
||||
if (distance >= -1 && distance <= 1) return
|
||||
|
||||
for (let i = 0; i < checkboxes.length; i++) {
|
||||
for (let i = 0; i < checkboxes.length; i++)
|
||||
if ((thisIndex > lastIndex && i > lastIndex && i < thisIndex) ||
|
||||
(thisIndex < lastIndex && i > thisIndex && i < lastIndex)) {
|
||||
checkboxes[i].checked = true
|
||||
page.selected[currentView].push(page.getItemID(checkboxes[i]))
|
||||
}
|
||||
}
|
||||
|
||||
localStorage[LS_KEYS.selected.uploads] = JSON.stringify(page.selected[currentView])
|
||||
page.checkboxes[currentView] = checkboxes
|
||||
@ -665,27 +657,24 @@ page.selectInBetween = function (element, lastElement) {
|
||||
page.select = function (element, event) {
|
||||
const currentView = page.currentView
|
||||
const lastSelected = page.lastSelected[currentView]
|
||||
if (event.shiftKey && lastSelected) {
|
||||
if (event.shiftKey && lastSelected)
|
||||
page.selectInBetween(element, lastSelected)
|
||||
} else {
|
||||
else
|
||||
page.lastSelected[currentView] = element
|
||||
}
|
||||
|
||||
const id = page.getItemID(element)
|
||||
if (isNaN(id)) { return }
|
||||
if (isNaN(id)) return
|
||||
|
||||
const selected = page.selected[currentView]
|
||||
if (!selected.includes(id) && element.checked) {
|
||||
if (!selected.includes(id) && element.checked)
|
||||
selected.push(id)
|
||||
} else if (selected.includes(id) && !element.checked) {
|
||||
else if (selected.includes(id) && !element.checked)
|
||||
selected.splice(selected.indexOf(id), 1)
|
||||
}
|
||||
|
||||
if (selected.length) {
|
||||
if (selected.length)
|
||||
localStorage[LS_KEYS.selected[currentView]] = JSON.stringify(selected)
|
||||
} else {
|
||||
else
|
||||
localStorage.removeItem(LS_KEYS.selected[currentView])
|
||||
}
|
||||
|
||||
page.selected[currentView] = selected
|
||||
}
|
||||
@ -694,9 +683,8 @@ page.clearSelection = function () {
|
||||
const currentView = page.currentView
|
||||
const selected = page.selected[currentView]
|
||||
const count = selected.length
|
||||
if (!count) {
|
||||
if (!count)
|
||||
return swal('An error occurred!', `You have not selected any ${currentView}.`, 'error')
|
||||
}
|
||||
|
||||
const suffix = count === 1 ? currentView.substring(0, currentView.length - 1) : currentView
|
||||
return swal({
|
||||
@ -704,20 +692,18 @@ page.clearSelection = function () {
|
||||
text: `You are going to unselect ${count} ${suffix}.`,
|
||||
buttons: true
|
||||
}).then(function (proceed) {
|
||||
if (!proceed) { return }
|
||||
if (!proceed) return
|
||||
|
||||
const checkboxes = page.checkboxes[currentView]
|
||||
for (let i = 0; i < checkboxes.length; i++) {
|
||||
if (checkboxes[i].checked) {
|
||||
for (let i = 0; i < checkboxes.length; i++)
|
||||
if (checkboxes[i].checked)
|
||||
checkboxes[i].checked = false
|
||||
}
|
||||
}
|
||||
|
||||
localStorage.removeItem(LS_KEYS.selected[currentView])
|
||||
page.selected[currentView] = []
|
||||
|
||||
const selectAll = document.getElementById('selectAll')
|
||||
if (selectAll) { selectAll.checked = false }
|
||||
if (selectAll) selectAll.checked = false
|
||||
|
||||
return swal('Cleared selection!', `Unselected ${count} ${suffix}.`, 'success')
|
||||
})
|
||||
@ -738,18 +724,17 @@ page.deleteFile = function (id) {
|
||||
}
|
||||
}
|
||||
}).then(function (proceed) {
|
||||
if (!proceed) { return }
|
||||
if (!proceed) return
|
||||
|
||||
axios.post('api/upload/delete', { id }).then(function (response) {
|
||||
if (!response) { return }
|
||||
if (!response) return
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
swal('Deleted!', 'The file has been deleted.', 'success')
|
||||
page.getUploads(page.views.uploads)
|
||||
@ -762,9 +747,8 @@ page.deleteFile = function (id) {
|
||||
|
||||
page.deleteSelectedFiles = function () {
|
||||
const count = page.selected.uploads.length
|
||||
if (!count) {
|
||||
if (!count)
|
||||
return swal('An error occurred!', 'You have not selected any uploads.', 'error')
|
||||
}
|
||||
|
||||
const suffix = `file${count === 1 ? '' : 's'}`
|
||||
swal({
|
||||
@ -780,21 +764,20 @@ page.deleteSelectedFiles = function () {
|
||||
}
|
||||
}
|
||||
}).then(function (proceed) {
|
||||
if (!proceed) { return }
|
||||
if (!proceed) return
|
||||
|
||||
axios.post('api/upload/bulkdelete', {
|
||||
field: 'id',
|
||||
values: page.selected.uploads
|
||||
}).then(function (bulkdelete) {
|
||||
if (!bulkdelete) { return }
|
||||
if (!bulkdelete) return
|
||||
|
||||
if (bulkdelete.data.success === false) {
|
||||
if (bulkdelete.data.success === false)
|
||||
if (bulkdelete.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', bulkdelete.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
let deleted = count
|
||||
if (bulkdelete.data.failed && bulkdelete.data.failed.length) {
|
||||
@ -802,9 +785,8 @@ page.deleteSelectedFiles = function () {
|
||||
page.selected.uploads = page.selected.uploads.filter(function (id) {
|
||||
return bulkdelete.data.failed.includes(id)
|
||||
})
|
||||
} else {
|
||||
} else
|
||||
page.selected.uploads = []
|
||||
}
|
||||
|
||||
localStorage[LS_KEYS.selected.uploads] = JSON.stringify(page.selected.uploads)
|
||||
|
||||
@ -848,9 +830,8 @@ page.deleteFileByNames = function () {
|
||||
return n.trim().length
|
||||
})
|
||||
const count = names.length
|
||||
if (!count) {
|
||||
if (!count)
|
||||
return swal('An error occurred!', 'You have not entered any file names.', 'error')
|
||||
}
|
||||
|
||||
const suffix = `file${count === 1 ? '' : 's'}`
|
||||
swal({
|
||||
@ -866,26 +847,24 @@ page.deleteFileByNames = function () {
|
||||
}
|
||||
}
|
||||
}).then(function (proceed) {
|
||||
if (!proceed) { return }
|
||||
if (!proceed) return
|
||||
|
||||
axios.post('api/upload/bulkdelete', {
|
||||
field: 'name',
|
||||
values: names
|
||||
}).then(function (bulkdelete) {
|
||||
if (!bulkdelete) { return }
|
||||
if (!bulkdelete) return
|
||||
|
||||
if (bulkdelete.data.success === false) {
|
||||
if (bulkdelete.data.success === false)
|
||||
if (bulkdelete.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', bulkdelete.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
let deleted = count
|
||||
if (bulkdelete.data.failed && bulkdelete.data.failed.length) {
|
||||
if (bulkdelete.data.failed && bulkdelete.data.failed.length)
|
||||
deleted -= bulkdelete.data.failed.length
|
||||
}
|
||||
|
||||
document.getElementById('names').value = bulkdelete.data.failed.join('\n')
|
||||
swal('Deleted!', `${deleted} file${deleted === 1 ? ' has' : 's have'} been deleted.`, 'success')
|
||||
@ -898,19 +877,18 @@ page.deleteFileByNames = function () {
|
||||
|
||||
page.addSelectedFilesToAlbum = function () {
|
||||
const count = page.selected.uploads.length
|
||||
if (!count) {
|
||||
if (!count)
|
||||
return swal('An error occurred!', 'You have not selected any uploads.', 'error')
|
||||
}
|
||||
|
||||
page.addFilesToAlbum(page.selected.uploads, function (failed) {
|
||||
if (!failed) { return }
|
||||
if (failed.length) {
|
||||
if (!failed) return
|
||||
if (failed.length)
|
||||
page.selected.uploads = page.selected.uploads.filter(function (id) {
|
||||
return failed.includes(id)
|
||||
})
|
||||
} else {
|
||||
else
|
||||
page.selected.uploads = []
|
||||
}
|
||||
|
||||
localStorage[LS_KEYS.selected.uploads] = JSON.stringify(page.selected.uploads)
|
||||
page.getUploads(page.views.uploads)
|
||||
})
|
||||
@ -918,7 +896,7 @@ page.addSelectedFilesToAlbum = function () {
|
||||
|
||||
page.addSingleFileToAlbum = function (id) {
|
||||
page.addFilesToAlbum([id], function (failed) {
|
||||
if (!failed) { return }
|
||||
if (!failed) return
|
||||
page.getUploads(page.views.uploads)
|
||||
})
|
||||
}
|
||||
@ -955,37 +933,34 @@ page.addFilesToAlbum = function (ids, callback) {
|
||||
}
|
||||
}
|
||||
}).then(function (choose) {
|
||||
if (!choose) { return }
|
||||
if (!choose) return
|
||||
|
||||
const albumid = parseInt(document.getElementById('swalAlbum').value)
|
||||
if (isNaN(albumid)) {
|
||||
if (isNaN(albumid))
|
||||
return swal('An error occurred!', 'You did not choose an album.', 'error')
|
||||
}
|
||||
|
||||
axios.post('api/albums/addfiles', {
|
||||
ids,
|
||||
albumid
|
||||
}).then(function (add) {
|
||||
if (!add) { return }
|
||||
if (!add) return
|
||||
|
||||
if (add.data.success === false) {
|
||||
if (add.data.description === 'No token provided') {
|
||||
if (add.data.description === 'No token provided')
|
||||
page.verifyToken(page.token)
|
||||
} else {
|
||||
else
|
||||
swal('An error occurred!', add.data.description, 'error')
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let added = ids.length
|
||||
if (add.data.failed && add.data.failed.length) {
|
||||
if (add.data.failed && add.data.failed.length)
|
||||
added -= add.data.failed.length
|
||||
}
|
||||
|
||||
const suffix = `file${ids.length === 1 ? '' : 's'}`
|
||||
if (!added) {
|
||||
if (!added)
|
||||
return swal('An error occurred!', `Could not add the ${suffix} to the album.`, 'error')
|
||||
}
|
||||
|
||||
swal('Woohoo!', `Successfully ${albumid < 0 ? 'removed' : 'added'} ${added} ${suffix} ${albumid < 0 ? 'from' : 'to'} the album.`, 'success')
|
||||
return callback(add.data.failed)
|
||||
@ -1001,17 +976,17 @@ page.addFilesToAlbum = function (ids, callback) {
|
||||
// Get albums list then update content of swal
|
||||
axios.get('api/albums').then(function (list) {
|
||||
if (list.data.success === false) {
|
||||
if (list.data.description === 'No token provided') {
|
||||
if (list.data.description === 'No token provided')
|
||||
page.verifyToken(page.token)
|
||||
} else {
|
||||
else
|
||||
swal('An error occurred!', list.data.description, 'error')
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const select = document.getElementById('swalAlbum')
|
||||
// If the prompt was replaced, the container would be missing
|
||||
if (!select) { return }
|
||||
if (!select) return
|
||||
select.innerHTML += list.data.albums
|
||||
.map(function (album) {
|
||||
return `<option value="${album.id}">${album.name}</option>`
|
||||
@ -1027,15 +1002,14 @@ page.addFilesToAlbum = function (ids, callback) {
|
||||
|
||||
page.getAlbums = function () {
|
||||
axios.get('api/albums').then(function (response) {
|
||||
if (!response) { return }
|
||||
if (!response) return
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
page.cache.albums = {}
|
||||
|
||||
@ -1140,7 +1114,7 @@ page.getAlbums = function () {
|
||||
|
||||
page.editAlbum = function (id) {
|
||||
const album = page.cache.albums[id]
|
||||
if (!album) { return }
|
||||
if (!album) return
|
||||
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = `
|
||||
@ -1191,7 +1165,7 @@ page.editAlbum = function (id) {
|
||||
}
|
||||
}
|
||||
}).then(function (value) {
|
||||
if (!value) { return }
|
||||
if (!value) return
|
||||
|
||||
axios.post('api/albums/edit', {
|
||||
id,
|
||||
@ -1201,23 +1175,21 @@ page.editAlbum = function (id) {
|
||||
public: document.getElementById('swalPublic').checked,
|
||||
requestLink: document.getElementById('swalRequestLink').checked
|
||||
}).then(function (response) {
|
||||
if (!response) { return }
|
||||
if (!response) return
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
if (response.data.identifier) {
|
||||
if (response.data.identifier)
|
||||
swal('Success!', `Your album's new identifier is: ${response.data.identifier}.`, 'success')
|
||||
} else if (response.data.name !== album.name) {
|
||||
else if (response.data.name !== album.name)
|
||||
swal('Success!', `Your album was renamed to: ${response.data.name}.`, 'success')
|
||||
} else {
|
||||
else
|
||||
swal('Success!', 'Your album was edited!', 'success')
|
||||
}
|
||||
|
||||
page.getAlbumsSidebar()
|
||||
page.getAlbums()
|
||||
@ -1248,19 +1220,18 @@ page.deleteAlbum = function (id) {
|
||||
}
|
||||
}
|
||||
}).then(function (proceed) {
|
||||
if (!proceed) { return }
|
||||
if (!proceed) return
|
||||
|
||||
axios.post('api/albums/delete', {
|
||||
id,
|
||||
purge: proceed === 'purge'
|
||||
}).then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
swal('Deleted!', 'Your album has been deleted.', 'success')
|
||||
page.getAlbumsSidebar()
|
||||
@ -1279,17 +1250,16 @@ page.submitAlbum = function (element) {
|
||||
name: document.getElementById('albumName').value,
|
||||
description: document.getElementById('albumDescription').value
|
||||
}).then(function (response) {
|
||||
if (!response) { return }
|
||||
if (!response) return
|
||||
|
||||
page.isLoading(element, false)
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
swal('Woohoo!', 'Album was created successfully', 'success')
|
||||
page.getAlbumsSidebar()
|
||||
@ -1303,20 +1273,19 @@ page.submitAlbum = function (element) {
|
||||
|
||||
page.getAlbumsSidebar = function () {
|
||||
axios.get('api/albums/sidebar').then(function (response) {
|
||||
if (!response) { return }
|
||||
if (!response) return
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
const albumsContainer = document.getElementById('albumsContainer')
|
||||
albumsContainer.innerHTML = ''
|
||||
|
||||
if (response.data.albums === undefined) { return }
|
||||
if (response.data.albums === undefined) return
|
||||
|
||||
for (let i = 0; i < response.data.albums.length; i++) {
|
||||
const album = response.data.albums[i]
|
||||
@ -1345,13 +1314,12 @@ page.getAlbum = function (album) {
|
||||
|
||||
page.changeFileLength = function () {
|
||||
axios.get('api/filelength/config').then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
// Shorter vars
|
||||
const { max, min } = response.data.config
|
||||
@ -1397,13 +1365,12 @@ page.setFileLength = function (fileLength, element) {
|
||||
axios.post('api/filelength/change', { fileLength }).then(function (response) {
|
||||
page.isLoading(element, false)
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
swal({
|
||||
title: 'Woohoo!',
|
||||
@ -1421,13 +1388,12 @@ page.setFileLength = function (fileLength, element) {
|
||||
|
||||
page.changeToken = function () {
|
||||
axios.get('api/tokens').then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
page.dom.innerHTML = `
|
||||
<h2 class="subtitle">Manage your token</h2>
|
||||
@ -1463,13 +1429,12 @@ page.getNewToken = function (element) {
|
||||
axios.post('api/tokens/change').then(function (response) {
|
||||
page.isLoading(element, false)
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
swal({
|
||||
title: 'Woohoo!',
|
||||
@ -1517,15 +1482,14 @@ page.changePassword = function () {
|
||||
page.fadeIn()
|
||||
|
||||
document.getElementById('sendChangePassword').addEventListener('click', function () {
|
||||
if (document.getElementById('password').value === document.getElementById('passwordConfirm').value) {
|
||||
if (document.getElementById('password').value === document.getElementById('passwordConfirm').value)
|
||||
page.sendNewPassword(document.getElementById('password').value, this)
|
||||
} else {
|
||||
else
|
||||
swal({
|
||||
title: 'Password mismatch!',
|
||||
text: 'Your passwords do not match, please try again.',
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -1535,13 +1499,12 @@ page.sendNewPassword = function (pass, element) {
|
||||
axios.post('api/password/change', { password: pass }).then(function (response) {
|
||||
page.isLoading(element, false)
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
swal({
|
||||
title: 'Woohoo!',
|
||||
@ -1560,9 +1523,8 @@ page.sendNewPassword = function (pass, element) {
|
||||
page.setActiveMenu = function (activeItem) {
|
||||
const menu = document.getElementById('menu')
|
||||
const items = menu.getElementsByTagName('a')
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
for (let i = 0; i < items.length; i++)
|
||||
items[i].classList.remove('is-active')
|
||||
}
|
||||
|
||||
activeItem.classList.add('is-active')
|
||||
}
|
||||
@ -1585,11 +1547,11 @@ page.getPrettyBytes = num => {
|
||||
// MIT License
|
||||
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
|
||||
if (!Number.isFinite(num)) { return num }
|
||||
if (!Number.isFinite(num)) return num
|
||||
|
||||
const neg = num < 0
|
||||
if (neg) { num = -num }
|
||||
if (num < 1) { return `${neg ? '-' : ''}${num}B` }
|
||||
if (neg) num = -num
|
||||
if (num < 1) return `${neg ? '-' : ''}${num}B`
|
||||
|
||||
const exponent = Math.min(Math.floor(Math.log10(num) / 3), page.byteUnits.length - 1)
|
||||
const numStr = Number((num / Math.pow(1000, exponent)).toPrecision(3))
|
||||
@ -1599,26 +1561,24 @@ page.getPrettyBytes = num => {
|
||||
}
|
||||
|
||||
page.getUsers = ({ pageNum } = {}, element) => {
|
||||
if (element) { page.isLoading(element, true) }
|
||||
if (pageNum === undefined) { pageNum = 0 }
|
||||
if (element) page.isLoading(element, true)
|
||||
if (pageNum === undefined) pageNum = 0
|
||||
|
||||
if (!page.permissions.admin) {
|
||||
if (!page.permissions.admin)
|
||||
return swal('An error occurred!', 'You can not do this!', 'error')
|
||||
}
|
||||
|
||||
const url = `api/users/${pageNum}`
|
||||
axios.get(url).then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
if (pageNum && (response.data.users.length === 0)) {
|
||||
// Only remove loading class here, since beyond this the entire page will be replaced anyways
|
||||
if (element) { page.isLoading(element, false) }
|
||||
if (element) page.isLoading(element, false)
|
||||
return swal('An error occurred!', 'There are no more users!', 'error')
|
||||
}
|
||||
|
||||
@ -1691,11 +1651,11 @@ page.getUsers = ({ pageNum } = {}, element) => {
|
||||
for (let i = 0; i < response.data.users.length; i++) {
|
||||
const user = response.data.users[i]
|
||||
const selected = page.selected.users.includes(user.id)
|
||||
if (!selected && allSelected) { allSelected = false }
|
||||
if (!selected && allSelected) allSelected = false
|
||||
|
||||
let displayGroup = null
|
||||
for (const group of Object.keys(user.groups)) {
|
||||
if (!user.groups[group]) { break }
|
||||
if (!user.groups[group]) break
|
||||
displayGroup = group
|
||||
}
|
||||
|
||||
@ -1744,12 +1704,12 @@ page.getUsers = ({ pageNum } = {}, element) => {
|
||||
|
||||
if (allSelected && response.data.users.length) {
|
||||
const selectAll = document.getElementById('selectAll')
|
||||
if (selectAll) { selectAll.checked = true }
|
||||
if (selectAll) selectAll.checked = true
|
||||
}
|
||||
|
||||
page.views.users.pageNum = response.data.users.length ? pageNum : 0
|
||||
}).catch(function (error) {
|
||||
if (element) { page.isLoading(element, false) }
|
||||
if (element) page.isLoading(element, false)
|
||||
console.log(error)
|
||||
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
})
|
||||
@ -1757,7 +1717,7 @@ page.getUsers = ({ pageNum } = {}, element) => {
|
||||
|
||||
page.editUser = function (id) {
|
||||
const user = page.cache.users[id]
|
||||
if (!user) { return }
|
||||
if (!user) return
|
||||
|
||||
const groupOptions = Object.keys(page.permissions).map((g, i, a) => {
|
||||
const selected = g === user.displayGroup
|
||||
@ -1812,7 +1772,7 @@ page.editUser = function (id) {
|
||||
}
|
||||
}
|
||||
}).then(function (value) {
|
||||
if (!value) { return }
|
||||
if (!value) return
|
||||
|
||||
axios.post('api/users/edit', {
|
||||
id,
|
||||
@ -1821,15 +1781,14 @@ page.editUser = function (id) {
|
||||
enabled: document.getElementById('swalEnabled').checked,
|
||||
resetPassword: document.getElementById('swalResetPassword').checked
|
||||
}).then(function (response) {
|
||||
if (!response) { return }
|
||||
if (!response) return
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
if (response.data.description === 'No token provided') {
|
||||
return page.verifyToken(page.token)
|
||||
} else {
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
if (response.data.password) {
|
||||
const div = document.createElement('div')
|
||||
@ -1842,11 +1801,10 @@ page.editUser = function (id) {
|
||||
icon: 'success',
|
||||
content: div
|
||||
})
|
||||
} else if (response.data.name !== user.name) {
|
||||
} else if (response.data.name !== user.name)
|
||||
swal('Success!', `${user.username} was renamed into: ${response.data.name}.`, 'success')
|
||||
} else {
|
||||
else
|
||||
swal('Success!', 'The user was edited!', 'success')
|
||||
}
|
||||
|
||||
page.getUsers(page.views.users)
|
||||
}).catch(function (error) {
|
||||
@ -1896,14 +1854,13 @@ page.disableUser = function (id) {
|
||||
|
||||
window.onload = function () {
|
||||
// Add 'no-touch' class to non-touch devices
|
||||
if (!('ontouchstart' in document.documentElement)) {
|
||||
if (!('ontouchstart' in document.documentElement))
|
||||
document.documentElement.classList.add('no-touch')
|
||||
}
|
||||
|
||||
const selectedKeys = ['uploads', 'users']
|
||||
for (const selectedKey of selectedKeys) {
|
||||
const ls = localStorage[LS_KEYS.selected[selectedKey]]
|
||||
if (ls) { page.selected[selectedKey] = JSON.parse(ls) }
|
||||
if (ls) page.selected[selectedKey] = JSON.parse(ls)
|
||||
}
|
||||
|
||||
page.preparePage()
|
||||
|
@ -40,7 +40,7 @@ page.checkIfPublic = function () {
|
||||
}
|
||||
|
||||
page.preparePage = function () {
|
||||
if (page.private) {
|
||||
if (page.private)
|
||||
if (page.token) {
|
||||
return page.verifyToken(page.token, true)
|
||||
} else {
|
||||
@ -48,32 +48,29 @@ page.preparePage = function () {
|
||||
button.href = 'auth'
|
||||
button.classList.remove('is-loading')
|
||||
|
||||
if (page.enableUserAccounts) {
|
||||
if (page.enableUserAccounts)
|
||||
button.innerText = 'Anonymous upload is disabled. Log in to page.'
|
||||
} else {
|
||||
else
|
||||
button.innerText = 'Running in private mode. Log in to page.'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
else
|
||||
return page.prepareUpload()
|
||||
}
|
||||
}
|
||||
|
||||
page.verifyToken = function (token, reloadOnError) {
|
||||
if (reloadOnError === undefined) { reloadOnError = false }
|
||||
if (reloadOnError === undefined) reloadOnError = false
|
||||
|
||||
axios.post('api/tokens/verify', { token }).then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
return swal({
|
||||
title: 'An error occurred!',
|
||||
text: response.data.description,
|
||||
icon: 'error'
|
||||
}).then(function () {
|
||||
if (!reloadOnError) { return }
|
||||
if (!reloadOnError) return
|
||||
localStorage.removeItem('token')
|
||||
location.reload()
|
||||
})
|
||||
}
|
||||
|
||||
localStorage.token = token
|
||||
page.token = token
|
||||
@ -102,9 +99,8 @@ page.prepareUpload = function () {
|
||||
document.getElementById('maxFileSize').innerHTML = `Maximum upload size per file is ${page.maxFileSize}`
|
||||
document.getElementById('loginToUpload').style.display = 'none'
|
||||
|
||||
if (!page.token && page.enableUserAccounts) {
|
||||
if (!page.token && page.enableUserAccounts)
|
||||
document.getElementById('loginLinkText').innerHTML = 'Create an account and keep track of your uploads'
|
||||
}
|
||||
|
||||
const previewNode = document.querySelector('#tpl')
|
||||
page.previewTemplate = previewNode.innerHTML
|
||||
@ -116,18 +112,17 @@ page.prepareUpload = function () {
|
||||
if (tabs) {
|
||||
tabs.style.display = 'flex'
|
||||
const items = tabs.getElementsByTagName('li')
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
for (let i = 0; i < items.length; i++)
|
||||
items[i].addEventListener('click', function () {
|
||||
page.setActiveTab(this.dataset.id)
|
||||
})
|
||||
}
|
||||
|
||||
document.getElementById('uploadUrls').addEventListener('click', function () {
|
||||
page.uploadUrls(this)
|
||||
})
|
||||
page.setActiveTab('tab-files')
|
||||
} else {
|
||||
} else
|
||||
document.getElementById('tab-files').style.display = 'block'
|
||||
}
|
||||
}
|
||||
|
||||
page.prepareAlbums = function () {
|
||||
@ -143,13 +138,12 @@ page.prepareAlbums = function () {
|
||||
token: page.token
|
||||
}
|
||||
}).then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
|
||||
// If the user doesn't have any albums we don't really need to display
|
||||
// an album selection
|
||||
if (!response.data.albums.length) { return }
|
||||
if (!response.data.albums.length) return
|
||||
|
||||
// Loop through the albums and create an option for each album
|
||||
for (let i = 0; i < response.data.albums.length; i++) {
|
||||
@ -230,13 +224,12 @@ page.prepareDropzone = function () {
|
||||
}).then(function (response) {
|
||||
file.previewElement.querySelector('.progress').style.display = 'none'
|
||||
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
file.previewElement.querySelector('.error').innerHTML = response.data.description
|
||||
}
|
||||
|
||||
if (response.data.files && response.data.files[0]) {
|
||||
if (response.data.files && response.data.files[0])
|
||||
page.updateTemplate(file, response.data.files[0])
|
||||
}
|
||||
|
||||
return done()
|
||||
}).catch(function (error) {
|
||||
return {
|
||||
@ -254,29 +247,27 @@ page.prepareDropzone = function () {
|
||||
|
||||
// Add the selected albumid, if an album is selected, as a header
|
||||
page.dropzone.on('sending', function (file, xhr) {
|
||||
if (file.upload.chunked) { return }
|
||||
if (page.album) { xhr.setRequestHeader('albumid', page.album) }
|
||||
if (file.upload.chunked) return
|
||||
if (page.album) xhr.setRequestHeader('albumid', page.album)
|
||||
})
|
||||
|
||||
// Update the total progress bar
|
||||
page.dropzone.on('uploadprogress', function (file, progress) {
|
||||
if (file.upload.chunked && progress === 100) { return }
|
||||
if (file.upload.chunked && progress === 100) return
|
||||
file.previewElement.querySelector('.progress').setAttribute('value', progress)
|
||||
file.previewElement.querySelector('.progress').innerHTML = `${progress}%`
|
||||
})
|
||||
|
||||
page.dropzone.on('success', function (file, response) {
|
||||
if (!response) { return }
|
||||
if (!response) return
|
||||
file.previewElement.querySelector('.progress').style.display = 'none'
|
||||
// file.previewElement.querySelector('.name').innerHTML = file.name
|
||||
|
||||
if (response.success === false) {
|
||||
if (response.success === false)
|
||||
file.previewElement.querySelector('.error').innerHTML = response.description
|
||||
}
|
||||
|
||||
if (response.files && response.files[0]) {
|
||||
if (response.files && response.files[0])
|
||||
page.updateTemplate(file, response.files[0])
|
||||
}
|
||||
})
|
||||
|
||||
page.dropzone.on('error', function (file, error) {
|
||||
@ -285,18 +276,18 @@ page.prepareDropzone = function () {
|
||||
file.previewElement.querySelector('.error').innerHTML = error.description || error
|
||||
})
|
||||
|
||||
if (typeof page.prepareShareX === 'function') { page.prepareShareX() }
|
||||
if (typeof page.prepareShareX === 'function') page.prepareShareX()
|
||||
}
|
||||
|
||||
page.uploadUrls = function (button) {
|
||||
const tabDiv = document.getElementById('tab-urls')
|
||||
if (!tabDiv) { return }
|
||||
if (!tabDiv) return
|
||||
|
||||
if (button.classList.contains('is-loading')) { return }
|
||||
if (button.classList.contains('is-loading')) return
|
||||
button.classList.add('is-loading')
|
||||
|
||||
function done (error) {
|
||||
if (error) { swal('An error occurred!', error, 'error') }
|
||||
if (error) swal('An error occurred!', error, 'error')
|
||||
button.classList.remove('is-loading')
|
||||
}
|
||||
|
||||
@ -308,10 +299,9 @@ page.uploadUrls = function (button) {
|
||||
.filter(function (url) { return url.trim().length })
|
||||
document.getElementById('urls').value = urls.join('\n')
|
||||
|
||||
if (!urls.length) {
|
||||
if (!urls.length)
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
return done('You have not entered any URLs.')
|
||||
}
|
||||
|
||||
tabDiv.getElementsByClassName('uploads')[0].style.display = 'block'
|
||||
const files = urls.map(function (url) {
|
||||
@ -327,17 +317,17 @@ page.uploadUrls = function (button) {
|
||||
})
|
||||
|
||||
function post (i) {
|
||||
if (i === files.length) { return done() }
|
||||
if (i === files.length) return done()
|
||||
|
||||
const file = files[i]
|
||||
|
||||
function posted (result) {
|
||||
file.previewElement.querySelector('.progress').style.display = 'none'
|
||||
if (result.success) {
|
||||
if (result.success)
|
||||
page.updateTemplate(file, result.files[0])
|
||||
} else {
|
||||
else
|
||||
file.previewElement.querySelector('.error').innerHTML = result.description
|
||||
}
|
||||
|
||||
return post(i + 1)
|
||||
}
|
||||
|
||||
@ -363,7 +353,7 @@ page.uploadUrls = function (button) {
|
||||
}
|
||||
|
||||
page.updateTemplate = function (file, response) {
|
||||
if (!response.url) { return }
|
||||
if (!response.url) return
|
||||
|
||||
const a = file.previewElement.querySelector('.link > a')
|
||||
const clipboard = file.previewElement.querySelector('.clipboard-mobile > .clipboard-js')
|
||||
@ -422,7 +412,7 @@ page.createAlbum = function () {
|
||||
}
|
||||
}
|
||||
}).then(function (value) {
|
||||
if (!value) { return }
|
||||
if (!value) return
|
||||
|
||||
const name = document.getElementById('swalName').value
|
||||
axios.post('api/albums', {
|
||||
@ -435,9 +425,8 @@ page.createAlbum = function () {
|
||||
token: page.token
|
||||
}
|
||||
}).then(function (response) {
|
||||
if (response.data.success === false) {
|
||||
if (response.data.success === false)
|
||||
return swal('An error occurred!', response.data.description, 'error')
|
||||
}
|
||||
|
||||
const option = document.createElement('option')
|
||||
option.value = response.data.id
|
||||
|
@ -46,7 +46,7 @@ page.doRenderSwal = function () {
|
||||
confirm: true
|
||||
}
|
||||
}).then(function (value) {
|
||||
if (!value) { return }
|
||||
if (!value) return
|
||||
const newValue = div.querySelector('#swalRender').checked ? undefined : '0'
|
||||
if (newValue !== localStorage.render) {
|
||||
newValue ? localStorage.render = newValue : localStorage.removeItem('render')
|
||||
@ -60,14 +60,14 @@ page.doRenderSwal = function () {
|
||||
|
||||
page.getRenderVersion = function () {
|
||||
const renderScript = document.getElementById('renderScript')
|
||||
if (!renderScript) { return '' }
|
||||
if (!renderScript) return ''
|
||||
const match = renderScript.src.match(/\?v=\w*$/)
|
||||
if (!match) { return '' }
|
||||
if (!match) return ''
|
||||
return match[0]
|
||||
}
|
||||
|
||||
page.doRender = function () {
|
||||
if (!page.renderRoot || !page.renderArray || !page.renderArray.length) { return }
|
||||
if (!page.renderRoot || !page.renderArray || !page.renderArray.length) return
|
||||
|
||||
let element
|
||||
if (localStorage.render === '0') {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* global page */
|
||||
|
||||
page.prepareShareX = function () {
|
||||
if (!page.token) { return }
|
||||
if (!page.token) return
|
||||
const origin = (location.hostname + location.pathname).replace(/\/(dashboard)?$/, '')
|
||||
const originClean = origin.replace(/\//g, '_')
|
||||
const sharexElement = document.getElementById('ShareX')
|
||||
|
Loading…
Reference in New Issue
Block a user