Various updates

* Switched ESLint + Aqua to Standard. I'm a big fan of Standard. Updated yarn.lock file too.

* Lots of refactors to follow the rules of Standard.

* Fixed issue with uploading as a not logged in user.
This commit is contained in:
Bobby Wibowo 2018-01-24 03:06:30 +07:00
parent da40ea71b1
commit bcdfcd7064
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
20 changed files with 2153 additions and 1759 deletions

View File

@ -81,4 +81,4 @@ module.exports = {
connection: { filename: './database/db' }, connection: { filename: './database/db' },
useNullAsDefault: true useNullAsDefault: true
} }
}; }

View File

@ -1,58 +1,58 @@
const config = require('../config.js'); const config = require('../config.js')
const db = require('knex')(config.database); const db = require('knex')(config.database)
const randomstring = require('randomstring'); const randomstring = require('randomstring')
const utils = require('./utilsController.js'); const utils = require('./utilsController.js')
const path = require('path'); const path = require('path')
const fs = require('fs'); const fs = require('fs')
const Zip = require('jszip'); const Zip = require('jszip')
const albumsController = {}; const albumsController = {}
albumsController.list = async (req, res, next) => { albumsController.list = async (req, res, next) => {
const user = await utils.authorize(req, res); const user = await utils.authorize(req, res)
const fields = ['id', 'name']; const fields = ['id', 'name']
if (req.params.sidebar === undefined) { if (req.params.sidebar === undefined) {
fields.push('timestamp'); fields.push('timestamp')
fields.push('identifier'); fields.push('identifier')
} }
const albums = await db.table('albums').select(fields).where({ enabled: 1, userid: user.id }); const albums = await db.table('albums').select(fields).where({ enabled: 1, userid: user.id })
if (req.params.sidebar !== undefined) { if (req.params.sidebar !== undefined) {
return res.json({ success: true, albums }); return res.json({ success: true, albums })
} }
let ids = []; let ids = []
for (let album of albums) { for (let album of albums) {
album.date = new Date(album.timestamp * 1000) album.date = new Date(album.timestamp * 1000)
album.date = utils.getPrettyDate(album.date) album.date = utils.getPrettyDate(album.date)
album.identifier = `${config.domain}/a/${album.identifier}`; album.identifier = `${config.domain}/a/${album.identifier}`
ids.push(album.id); ids.push(album.id)
} }
const files = await db.table('files').whereIn('albumid', ids).select('albumid'); const files = await db.table('files').whereIn('albumid', ids).select('albumid')
const albumsCount = {}; const albumsCount = {}
for (let id of ids) albumsCount[id] = 0; for (let id of ids) albumsCount[id] = 0
for (let file of files) albumsCount[file.albumid] += 1; for (let file of files) albumsCount[file.albumid] += 1
for (let album of albums) album.files = albumsCount[album.id]; for (let album of albums) album.files = albumsCount[album.id]
return res.json({ success: true, albums }); return res.json({ success: true, albums })
}; }
albumsController.create = async (req, res, next) => { albumsController.create = async (req, res, next) => {
const user = await utils.authorize(req, res); const user = await utils.authorize(req, res)
const name = req.body.name; const name = req.body.name
if (name === undefined || name === '') { if (name === undefined || name === '') {
return res.json({ success: false, description: 'No album name specified' }); return res.json({ success: false, description: 'No album name specified' })
} }
const album = await db.table('albums').where({ const album = await db.table('albums').where({
name: name, name: name,
enabled: 1, enabled: 1,
userid: user.id userid: user.id
}).first(); }).first()
if (album) { if (album) {
return res.json({ success: false, description: 'There\'s already an album with that name' }) return res.json({ success: false, description: 'There\'s already an album with that name' })
@ -64,61 +64,61 @@ albumsController.create = async (req, res, next) => {
userid: user.id, userid: user.id,
identifier: randomstring.generate(8), identifier: randomstring.generate(8),
timestamp: Math.floor(Date.now() / 1000) timestamp: Math.floor(Date.now() / 1000)
}); })
return res.json({ success: true }); return res.json({ success: true })
}; }
albumsController.delete = async (req, res, next) => { albumsController.delete = async (req, res, next) => {
const user = await utils.authorize(req, res); const user = await utils.authorize(req, res)
const id = req.body.id; const id = req.body.id
if (id === undefined || id === '') { if (id === undefined || id === '') {
return res.json({ success: false, description: 'No album specified' }); return res.json({ success: false, description: 'No album specified' })
} }
await db.table('albums').where({ id: id, userid: user.id }).update({ enabled: 0 }); await db.table('albums').where({ id: id, userid: user.id }).update({ enabled: 0 })
return res.json({ success: true }); return res.json({ success: true })
}; }
albumsController.rename = async (req, res, next) => { albumsController.rename = async (req, res, next) => {
const user = await utils.authorize(req, res); const user = await utils.authorize(req, res)
const id = req.body.id; const id = req.body.id
if (id === undefined || id === '') { if (id === undefined || id === '') {
return res.json({ success: false, description: 'No album specified' }); return res.json({ success: false, description: 'No album specified' })
} }
const name = req.body.name; const name = req.body.name
if (name === undefined || name === '') { if (name === undefined || name === '') {
return res.json({ success: false, description: 'No name specified' }); return res.json({ success: false, description: 'No name specified' })
} }
const album = await db.table('albums').where({ name: name, userid: user.id }).first(); const album = await db.table('albums').where({ name: name, userid: user.id }).first()
if (album) { if (album) {
return res.json({ success: false, description: 'Name already in use' }) return res.json({ success: false, description: 'Name already in use' })
} }
await db.table('albums').where({ id: id, userid: user.id }).update({ name: name }) await db.table('albums').where({ id: id, userid: user.id }).update({ name: name })
return res.json({ success: true }); return res.json({ success: true })
}; }
albumsController.get = async (req, res, next) => { albumsController.get = async (req, res, next) => {
const identifier = req.params.identifier; const identifier = req.params.identifier
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' }); if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' })
const album = await db.table('albums').where({ identifier, enabled: 1 }).first(); const album = await db.table('albums').where({ identifier, enabled: 1 }).first()
if (!album) return res.json({ success: false, description: 'Album not found' }); if (!album) return res.json({ success: false, description: 'Album not found' })
const title = album.name; const title = album.name
const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC'); const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC')
for (let file of files) { for (let file of files) {
file.file = `${config.domain}/${file.name}`; file.file = `${config.domain}/${file.name}`
const ext = path.extname(file.name).toLowerCase(); const ext = path.extname(file.name).toLowerCase()
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) { if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
file.thumb = `${config.domain}/thumbs/${file.name.slice(0, -ext.length)}.png`; file.thumb = `${config.domain}/thumbs/${file.name.slice(0, -ext.length)}.png`
} }
} }
@ -127,36 +127,35 @@ albumsController.get = async (req, res, next) => {
title: title, title: title,
count: files.length, count: files.length,
files files
}); })
}; }
albumsController.generateZip = async (req, res, next) => { albumsController.generateZip = async (req, res, next) => {
const identifier = req.params.identifier; const identifier = req.params.identifier
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' }); if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' })
if (!config.uploads.generateZips) return res.status(401).json({ success: false, description: 'Zip generation disabled' }); if (!config.uploads.generateZips) return res.status(401).json({ success: false, description: 'Zip generation disabled' })
const album = await db.table('albums').where({ identifier, enabled: 1 }).first(); const album = await db.table('albums').where({ identifier, enabled: 1 }).first()
if (!album) return res.json({ success: false, description: 'Album not found' }); if (!album) return res.json({ success: false, description: 'Album not found' })
if (album.zipGeneratedAt > album.editedAt) { if (album.zipGeneratedAt > album.editedAt) {
const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`); const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`)
const fileName = `${album.name}.zip`; const fileName = `${album.name}.zip`
return res.download(filePath, fileName); return res.download(filePath, fileName)
} else { } else {
console.log(`Generating zip for album identifier: ${identifier}`); console.log(`Generating zip for album identifier: ${identifier}`)
const files = await db.table('files').select('name').where('albumid', album.id); const files = await db.table('files').select('name').where('albumid', album.id)
if (files.length === 0) return res.json({ success: false, description: 'There are no files in the album' }); if (files.length === 0) return res.json({ success: false, description: 'There are no files in the album' })
const zipPath = path.join(__dirname, '..', config.uploads.folder, 'zips', `${album.identifier}.zip`); const zipPath = path.join(__dirname, '..', config.uploads.folder, 'zips', `${album.identifier}.zip`)
let archive = new Zip(); let archive = new Zip()
for (let file of files) { for (let file of files) {
try { try {
const exists = fs.statSync(path.join(__dirname, '..', config.uploads.folder, file.name)); // const exists = fs.statSync(path.join(__dirname, '..', config.uploads.folder, file.name))
archive.file(file.name, fs.readFileSync(path.join(__dirname, '..', config.uploads.folder, file.name))); archive.file(file.name, fs.readFileSync(path.join(__dirname, '..', config.uploads.folder, file.name)))
} catch (err) { } catch (err) {
console.log(err); console.log(err)
} }
} }
@ -164,16 +163,16 @@ albumsController.generateZip = async (req, res, next) => {
.generateNodeStream({ type: 'nodebuffer', streamFiles: true }) .generateNodeStream({ type: 'nodebuffer', streamFiles: true })
.pipe(fs.createWriteStream(zipPath)) .pipe(fs.createWriteStream(zipPath))
.on('finish', async () => { .on('finish', async () => {
console.log(`Generated zip for album identifier: ${identifier}`); console.log(`Generated zip for album identifier: ${identifier}`)
await db.table('albums') await db.table('albums')
.where('id', album.id) .where('id', album.id)
.update({ zipGeneratedAt: Math.floor(Date.now() / 1000) }); .update({ zipGeneratedAt: Math.floor(Date.now() / 1000) })
const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`); const filePath = path.join(config.uploads.folder, 'zips', `${identifier}.zip`)
const fileName = `${album.name}.zip`; const fileName = `${album.name}.zip`
return res.download(filePath, fileName); return res.download(filePath, fileName)
}); })
} }
}; }
module.exports = albumsController; module.exports = albumsController

View File

@ -1,41 +1,41 @@
const config = require('../config.js'); const config = require('../config.js')
const db = require('knex')(config.database); const db = require('knex')(config.database)
const bcrypt = require('bcrypt'); const bcrypt = require('bcrypt')
const randomstring = require('randomstring'); const randomstring = require('randomstring')
const utils = require('./utilsController.js'); const utils = require('./utilsController.js')
let authController = {}; let authController = {}
authController.verify = async (req, res, next) => { authController.verify = async (req, res, next) => {
const username = req.body.username; const username = req.body.username
const password = req.body.password; const password = req.body.password
if (username === undefined) return res.json({ success: false, description: 'No username 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 (password === undefined) return res.json({ success: false, description: 'No password provided' })
const user = await db.table('users').where('username', username).first(); const user = await db.table('users').where('username', username).first()
if (!user) return res.json({ success: false, description: 'Username doesn\'t exist' }); if (!user) return res.json({ success: false, description: 'Username doesn\'t exist' })
bcrypt.compare(password, user.password, (err, result) => { bcrypt.compare(password, user.password, (err, result) => {
if (err) { if (err) {
console.log(err); console.log(err)
return res.json({ success: false, description: 'There was an 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 }); return res.json({ success: true, token: user.token })
}); })
}; }
authController.register = async (req, res, next) => { 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' }); return res.json({ success: false, description: 'Register is disabled at the moment' })
} }
const username = req.body.username; const username = req.body.username
const password = req.body.password; const password = req.body.password
if (username === undefined) return res.json({ success: false, description: 'No username 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 (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' }) return res.json({ success: false, description: 'Username must have 4-32 characters' })
@ -44,43 +44,43 @@ authController.register = async (req, res, next) => {
return res.json({ success: false, description: 'Password must have 6-64 characters' }) return res.json({ success: false, description: 'Password must have 6-64 characters' })
} }
const user = await db.table('users').where('username', username).first(); 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 (err, hash) => { bcrypt.hash(password, 10, async (err, hash) => {
if (err) { if (err) {
console.log(err); console.log(err)
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻' }); return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻' })
} }
const token = randomstring.generate(64); const token = randomstring.generate(64)
await db.table('users').insert({ await db.table('users').insert({
username: username, username: username,
password: hash, password: hash,
token: token token: token
}); })
return res.json({ success: true, token: token }) return res.json({ success: true, token: token })
}); })
}; }
authController.changePassword = async (req, res, next) => { authController.changePassword = async (req, res, next) => {
const user = await utils.authorize(req, res); const user = await utils.authorize(req, res)
let password = req.body.password; let 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' }); return res.json({ success: false, description: 'Password must have 6-64 characters' })
} }
bcrypt.hash(password, 10, async (err, hash) => { bcrypt.hash(password, 10, async (err, hash) => {
if (err) { if (err) {
console.log(err); console.log(err)
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻' }); return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻' })
} }
await db.table('users').where('id', user.id).update({ password: hash }); await db.table('users').where('id', user.id).update({ password: hash })
return res.json({ success: true }); return res.json({ success: true })
}); })
}; }
module.exports = authController; module.exports = authController

View File

@ -1,34 +1,34 @@
const config = require('../config.js'); const config = require('../config.js')
const db = require('knex')(config.database); const db = require('knex')(config.database)
const randomstring = require('randomstring'); const randomstring = require('randomstring')
const utils = require('./utilsController.js'); const utils = require('./utilsController.js')
const tokenController = {}; const tokenController = {}
tokenController.verify = async (req, res, next) => { tokenController.verify = async (req, res, next) => {
const token = req.body.token; const token = req.body.token
if (token === undefined) return res.status(401).json({ success: false, description: 'No token provided' }); if (token === undefined) return res.status(401).json({ success: false, description: 'No token provided' })
const user = await db.table('users').where('token', token).first(); const user = await db.table('users').where('token', token).first()
if (!user) return res.status(401).json({ success: false, description: 'Invalid token' }); if (!user) return res.status(401).json({ success: false, description: 'Invalid token' })
return res.json({ success: true, username: user.username }); return res.json({ success: true, username: user.username })
}; }
tokenController.list = async (req, res, next) => { tokenController.list = async (req, res, next) => {
const user = await utils.authorize(req, res); const user = await utils.authorize(req, res)
return res.json({ success: true, token: user.token }); return res.json({ success: true, token: user.token })
}; }
tokenController.change = async (req, res, next) => { tokenController.change = async (req, res, next) => {
const user = await utils.authorize(req, res); const user = await utils.authorize(req, res)
const newtoken = randomstring.generate(64); const newtoken = randomstring.generate(64)
await db.table('users').where('token', user.token).update({ await db.table('users').where('token', user.token).update({
token: newtoken, token: newtoken,
timestamp: Math.floor(Date.now() / 1000) timestamp: Math.floor(Date.now() / 1000)
}); })
res.json({ success: true, token: newtoken }); res.json({ success: true, token: newtoken })
}; }
module.exports = tokenController; module.exports = tokenController

View File

@ -1,93 +1,93 @@
const config = require('../config.js'); const config = require('../config.js')
const path = require('path'); const path = require('path')
const multer = require('multer'); const multer = require('multer')
const randomstring = require('randomstring'); const randomstring = require('randomstring')
const db = require('knex')(config.database); const db = require('knex')(config.database)
const crypto = require('crypto'); const crypto = require('crypto')
const fs = require('fs'); const fs = require('fs')
const utils = require('./utilsController.js'); const utils = require('./utilsController.js')
const uploadsController = {}; const uploadsController = {}
const storage = multer.diskStorage({ const storage = multer.diskStorage({
destination: function(req, file, cb) { destination: function (req, file, cb) {
cb(null, path.join(__dirname, '..', config.uploads.folder)); cb(null, path.join(__dirname, '..', config.uploads.folder))
}, },
filename: function(req, file, cb) { filename: function (req, file, cb) {
cb(null, randomstring.generate(config.uploads.fileLength) + path.extname(file.originalname)); cb(null, randomstring.generate(config.uploads.fileLength) + path.extname(file.originalname))
} }
}); })
const upload = multer({ const upload = multer({
storage: storage, storage: storage,
limits: { fileSize: config.uploads.maxSize }, limits: { fileSize: config.uploads.maxSize },
fileFilter: function(req, file, cb) { fileFilter: function (req, file, cb) {
if (config.blockedExtensions !== undefined) { if (config.blockedExtensions !== undefined) {
if (config.blockedExtensions.some(extension => path.extname(file.originalname).toLowerCase() === extension)) { if (config.blockedExtensions.some(extension => path.extname(file.originalname).toLowerCase() === extension)) {
return cb('This file extension is not allowed'); return cb('This file extension is not allowed') // eslint-disable-line standard/no-callback-literal
} }
return cb(null, true); return cb(null, true)
} }
return cb(null, true); return cb(null, true)
} }
}).array('files[]'); }).array('files[]')
uploadsController.upload = async (req, res, next) => { uploadsController.upload = async (req, res, next) => {
if (config.private === true) { if (config.private === true) {
await utils.authorize(req, res); await utils.authorize(req, res)
} }
const token = req.headers.token || ''; const token = req.headers.token || ''
const user = await db.table('users').where('token', token).first(); const user = await db.table('users').where('token', token).first()
const albumid = req.headers.albumid || req.params.albumid; const albumid = req.headers.albumid || req.params.albumid
if (albumid && user) { if (albumid && user) {
const album = await db.table('albums').where({ id: albumid, userid: user.id }).first(); const album = await db.table('albums').where({ id: albumid, userid: user.id }).first()
if (!album) { if (!album) {
return res.json({ return res.json({
success: false, success: false,
description: 'Album doesn\'t exist or it doesn\'t belong to the user' description: 'Album doesn\'t exist or it doesn\'t belong to the user'
}); })
} }
return uploadsController.actuallyUpload(req, res, user, albumid); return uploadsController.actuallyUpload(req, res, user, albumid)
} }
return uploadsController.actuallyUpload(req, res, user, albumid); return uploadsController.actuallyUpload(req, res, user, albumid)
}; }
uploadsController.actuallyUpload = async (req, res, userid, album) => { uploadsController.actuallyUpload = async (req, res, userid, album) => {
upload(req, res, async err => { upload(req, res, async err => {
if (err) { if (err) {
console.error(err); console.error(err)
return res.json({ success: false, description: err }); return res.json({ success: false, description: err })
} }
if (req.files.length === 0) return res.json({ success: false, description: 'no-files' }); if (req.files.length === 0) return res.json({ success: false, description: 'no-files' })
const files = []; const files = []
const existingFiles = []; const existingFiles = []
let iteration = 1; let iteration = 1
req.files.forEach(async file => { req.files.forEach(async file => {
// Check if the file exists by checking hash and size // Check if the file exists by checking hash and size
let hash = crypto.createHash('md5'); let hash = crypto.createHash('md5')
let stream = fs.createReadStream(path.join(__dirname, '..', config.uploads.folder, file.filename)); let stream = fs.createReadStream(path.join(__dirname, '..', config.uploads.folder, file.filename))
stream.on('data', data => { stream.on('data', data => {
hash.update(data, 'utf8'); hash.update(data, 'utf8')
}); })
stream.on('end', async () => { stream.on('end', async () => {
const fileHash = hash.digest('hex'); const fileHash = hash.digest('hex')
const dbFile = await db.table('files') const dbFile = await db.table('files')
.where(function() { .where(function () {
if (userid === undefined) this.whereNull('userid'); if (userid === undefined) this.whereNull('userid')
else this.where('userid', userid.id); else this.where('userid', userid.id)
}) })
.where({ .where({
hash: fileHash, hash: fileHash,
size: file.size size: file.size
}) })
.first(); .first()
if (!dbFile) { if (!dbFile) {
files.push({ files.push({
@ -98,25 +98,25 @@ uploadsController.actuallyUpload = async (req, res, userid, album) => {
hash: fileHash, hash: fileHash,
ip: req.ip, ip: req.ip,
albumid: album, albumid: album,
userid: userid.id, userid: userid ? userid.id : null,
timestamp: Math.floor(Date.now() / 1000) timestamp: Math.floor(Date.now() / 1000)
}); })
} else { } else {
uploadsController.deleteFile(file.filename).then(() => {}).catch(err => console.error(err)); uploadsController.deleteFile(file.filename).then(() => {}).catch(err => console.error(err))
existingFiles.push(dbFile); existingFiles.push(dbFile)
} }
if (iteration === req.files.length) { if (iteration === req.files.length) {
return uploadsController.processFilesForDisplay(req, res, files, existingFiles); return uploadsController.processFilesForDisplay(req, res, files, existingFiles)
} }
iteration++; iteration++
}); })
}); })
}); })
}; }
uploadsController.processFilesForDisplay = async (req, res, files, existingFiles) => { uploadsController.processFilesForDisplay = async (req, res, files, existingFiles) => {
let basedomain = config.domain; let basedomain = config.domain
if (files.length === 0) { if (files.length === 0) {
return res.json({ return res.json({
success: true, success: true,
@ -125,13 +125,13 @@ uploadsController.processFilesForDisplay = async (req, res, files, existingFiles
name: file.name, name: file.name,
size: file.size, size: file.size,
url: `${basedomain}/${file.name}` url: `${basedomain}/${file.name}`
}; }
})
}) })
});
} }
await db.table('files').insert(files); await db.table('files').insert(files)
for (let efile of existingFiles) files.push(efile); for (let efile of existingFiles) files.push(efile)
res.json({ res.json({
success: true, success: true,
@ -140,113 +140,113 @@ uploadsController.processFilesForDisplay = async (req, res, files, existingFiles
name: file.name, name: file.name,
size: file.size, size: file.size,
url: `${basedomain}/${file.name}` url: `${basedomain}/${file.name}`
}; }
})
}) })
});
for (let file of files) { for (let file of files) {
let ext = path.extname(file.name).toLowerCase(); let ext = path.extname(file.name).toLowerCase()
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) { if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`; file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`
utils.generateThumbs(file); utils.generateThumbs(file)
} }
if (file.albumid) { if (file.albumid) {
db.table('albums').where('id', file.albumid).update('editedAt', file.timestamp).then(() => {}) db.table('albums').where('id', file.albumid).update('editedAt', file.timestamp).then(() => {})
.catch(error => { console.log(error); res.json({ success: false, description: 'Error updating album' }); }); .catch(error => { console.log(error); res.json({ success: false, description: 'Error updating album' }) })
} }
} }
}; }
uploadsController.delete = async (req, res) => { uploadsController.delete = async (req, res) => {
const user = await utils.authorize(req, res); const user = await utils.authorize(req, res)
const id = req.body.id; const id = req.body.id
if (id === undefined || id === '') { if (id === undefined || id === '') {
return res.json({ success: false, description: 'No file specified' }); return res.json({ success: false, description: 'No file specified' })
} }
const file = await db.table('files') const file = await db.table('files')
.where('id', id) .where('id', id)
.where(function() { .where(function () {
if (user.username !== 'root') { if (user.username !== 'root') {
this.where('userid', user.id); this.where('userid', user.id)
} }
}) })
.first(); .first()
try { try {
await uploadsController.deleteFile(file.name); await uploadsController.deleteFile(file.name)
await db.table('files').where('id', id).del(); await db.table('files').where('id', id).del()
if (file.albumid) { if (file.albumid) {
await db.table('albums').where('id', file.albumid).update('editedAt', Math.floor(Date.now() / 1000)); await db.table('albums').where('id', file.albumid).update('editedAt', Math.floor(Date.now() / 1000))
} }
} catch (err) { } catch (err) {
console.log(err); console.log(err)
} }
return res.json({ success: true }); return res.json({ success: true })
}; }
uploadsController.deleteFile = function(file) { uploadsController.deleteFile = function (file) {
const ext = path.extname(file).toLowerCase(); const ext = path.extname(file).toLowerCase()
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.stat(path.join(__dirname, '..', config.uploads.folder, file), (err, stats) => { fs.stat(path.join(__dirname, '..', config.uploads.folder, file), (err, stats) => {
if (err) { return reject(err); } if (err) { return reject(err) }
fs.unlink(path.join(__dirname, '..', config.uploads.folder, file), err => { fs.unlink(path.join(__dirname, '..', config.uploads.folder, file), err => {
if (err) { return reject(err); } if (err) { return reject(err) }
if (!utils.imageExtensions.includes(ext) && !utils.videoExtensions.includes(ext)) { if (!utils.imageExtensions.includes(ext) && !utils.videoExtensions.includes(ext)) {
return resolve(); return resolve()
} }
file = file.substr(0, file.lastIndexOf('.')) + '.png'; file = file.substr(0, file.lastIndexOf('.')) + '.png'
fs.stat(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), (err, stats) => { fs.stat(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), (err, stats) => {
if (err) { if (err) {
console.log(err); console.log(err)
return resolve(); return resolve()
} }
fs.unlink(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), err => { fs.unlink(path.join(__dirname, '..', config.uploads.folder, 'thumbs/', file), err => {
if (err) { return reject(err); } if (err) { return reject(err) }
return resolve(); return resolve()
}); })
}); })
}); })
}); })
}); })
}; }
uploadsController.list = async (req, res) => { uploadsController.list = async (req, res) => {
const user = await utils.authorize(req, res); const user = await utils.authorize(req, res)
let offset = req.params.page; let offset = req.params.page
if (offset === undefined) offset = 0; if (offset === undefined) offset = 0
const files = await db.table('files') const files = await db.table('files')
.where(function() { .where(function () {
if (req.params.id === undefined) this.where('id', '<>', ''); if (req.params.id === undefined) this.where('id', '<>', '')
else this.where('albumid', req.params.id); else this.where('albumid', req.params.id)
}) })
.where(function() { .where(function () {
if (user.username !== 'root') this.where('userid', user.id); if (user.username !== 'root') this.where('userid', user.id)
}) })
.orderBy('id', 'DESC') .orderBy('id', 'DESC')
.limit(25) .limit(25)
.offset(25 * offset) .offset(25 * offset)
.select('id', 'albumid', 'timestamp', 'name', 'userid'); .select('id', 'albumid', 'timestamp', 'name', 'userid')
const albums = await db.table('albums'); const albums = await db.table('albums')
let basedomain = config.domain; let basedomain = config.domain
let userids = []; let userids = []
for (let file of files) { for (let file of files) {
file.file = `${basedomain}/${file.name}`; file.file = `${basedomain}/${file.name}`
file.date = new Date(file.timestamp * 1000); file.date = new Date(file.timestamp * 1000)
file.date = utils.getPrettyDate(file.date); file.date = utils.getPrettyDate(file.date)
file.album = ''; file.album = ''
if (file.albumid !== undefined) { if (file.albumid !== undefined) {
for (let album of albums) { for (let album of albums) {
if (file.albumid === album.id) { if (file.albumid === album.id) {
file.album = album.name; file.album = album.name
} }
} }
} }
@ -254,32 +254,32 @@ uploadsController.list = async (req, res) => {
// Only push usernames if we are root // Only push usernames if we are root
if (user.username === 'root') { if (user.username === 'root') {
if (file.userid !== undefined && file.userid !== null && file.userid !== '') { if (file.userid !== undefined && file.userid !== null && file.userid !== '') {
userids.push(file.userid); userids.push(file.userid)
} }
} }
let ext = path.extname(file.name).toLowerCase(); let ext = path.extname(file.name).toLowerCase()
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) { if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`; file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`
} }
} }
// If we are a normal user, send response // If we are a normal user, send response
if (user.username !== 'root') return res.json({ success: true, files }); if (user.username !== 'root') return res.json({ success: true, files })
// If we are root but there are no uploads attached to a user, send response // If we are root 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); const users = await db.table('users').whereIn('id', userids)
for (let dbUser of users) { for (let dbUser of users) {
for (let file of files) { for (let file of files) {
if (file.userid === dbUser.id) { if (file.userid === dbUser.id) {
file.username = dbUser.username; file.username = dbUser.username
} }
} }
} }
return res.json({ success: true, files }); return res.json({ success: true, files })
}; }
module.exports = uploadsController; module.exports = uploadsController

View File

@ -1,40 +1,40 @@
const path = require('path'); const path = require('path')
const config = require('../config.js'); const config = require('../config.js')
const fs = require('fs'); const fs = require('fs')
const gm = require('gm'); const gm = require('gm')
const ffmpeg = require('fluent-ffmpeg'); const ffmpeg = require('fluent-ffmpeg')
const db = require('knex')(config.database); const db = require('knex')(config.database)
const utilsController = {}; const utilsController = {}
utilsController.imageExtensions = ['.jpg', '.jpeg', '.bmp', '.gif', '.png']; utilsController.imageExtensions = ['.jpg', '.jpeg', '.bmp', '.gif', '.png']
utilsController.videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov']; utilsController.videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov']
utilsController.getPrettyDate = function(date) { utilsController.getPrettyDate = function (date) {
return date.getFullYear() + '-' return date.getFullYear() + '-' +
+ (date.getMonth() + 1) + '-' (date.getMonth() + 1) + '-' +
+ date.getDate() + ' ' date.getDate() + ' ' +
+ (date.getHours() < 10 ? '0' : '') (date.getHours() < 10 ? '0' : '') +
+ date.getHours() + ':' date.getHours() + ':' +
+ (date.getMinutes() < 10 ? '0' : '') (date.getMinutes() < 10 ? '0' : '') +
+ date.getMinutes() + ':' date.getMinutes() + ':' +
+ (date.getSeconds() < 10 ? '0' : '') (date.getSeconds() < 10 ? '0' : '') +
+ date.getSeconds(); date.getSeconds()
} }
utilsController.authorize = async (req, res) => { utilsController.authorize = async (req, res) => {
const token = req.headers.token; const token = req.headers.token
if (token === undefined) return res.status(401).json({ success: false, description: 'No token provided' }); if (token === undefined) return res.status(401).json({ success: false, description: 'No token provided' })
const user = await db.table('users').where('token', token).first(); const user = await db.table('users').where('token', token).first()
if (!user) return res.status(401).json({ success: false, description: 'Invalid token' }); if (!user) return res.status(401).json({ success: false, description: 'Invalid token' })
return user; return user
}; }
utilsController.generateThumbs = function(file, basedomain) { utilsController.generateThumbs = function (file, basedomain) {
if (config.uploads.generateThumbnails !== true) return; if (config.uploads.generateThumbnails !== true) return
const ext = path.extname(file.name).toLowerCase(); const ext = path.extname(file.name).toLowerCase()
let thumbname = path.join(__dirname, '..', config.uploads.folder, 'thumbs', file.name.slice(0, -ext.length) + '.png'); let thumbname = path.join(__dirname, '..', config.uploads.folder, 'thumbs', file.name.slice(0, -ext.length) + '.png')
fs.access(thumbname, err => { fs.access(thumbname, err => {
if (err && err.code === 'ENOENT') { if (err && err.code === 'ENOENT') {
if (utilsController.videoExtensions.includes(ext)) { if (utilsController.videoExtensions.includes(ext)) {
@ -45,23 +45,23 @@ utilsController.generateThumbs = function(file, basedomain) {
folder: path.join(__dirname, '..', config.uploads.folder, 'thumbs'), folder: path.join(__dirname, '..', config.uploads.folder, 'thumbs'),
size: '200x?' size: '200x?'
}) })
.on('error', error => console.log('Error - ', error.message)); .on('error', error => console.log('Error - ', error.message))
} else { } else {
let size = { let size = {
width: 200, width: 200,
height: 200 height: 200
}; }
gm(path.join(__dirname, '..', config.uploads.folder, file.name)) gm(path.join(__dirname, '..', config.uploads.folder, file.name))
.resize(size.width, size.height + '>') .resize(size.width, size.height + '>')
.gravity('Center') .gravity('Center')
.extent(size.width, size.height) .extent(size.width, size.height)
.background('transparent') .background('transparent')
.write(thumbname, error => { .write(thumbname, error => {
if (error) console.log('Error - ', error); if (error) console.log('Error - ', error)
}); })
} }
} }
}); })
}; }
module.exports = utilsController; module.exports = utilsController

View File

@ -1,5 +1,4 @@
let init = function(db){ let init = function (db) {
// Create the tables we need to store galleries and files // Create the tables we need to store galleries and files
db.schema.createTableIfNotExists('albums', function (table) { db.schema.createTableIfNotExists('albums', function (table) {
table.increments() table.increments()
@ -31,10 +30,10 @@ let init = function(db){
table.integer('timestamp') table.integer('timestamp')
}).then(() => { }).then(() => {
db.table('users').where({username: 'root'}).then((user) => { db.table('users').where({username: 'root'}).then((user) => {
if(user.length > 0) return if (user.length > 0) return
require('bcrypt').hash('root', 10, function(err, hash) { require('bcrypt').hash('root', 10, function (err, hash) {
if(err) console.error('Error generating password hash for root') if (err) console.error('Error generating password hash for root')
db.table('users').insert({ db.table('users').insert({
username: 'root', username: 'root',

View File

@ -1,13 +1,13 @@
const config = require('../config.js'); const config = require('../config.js')
const db = require('knex')(config.database); const db = require('knex')(config.database)
const migration = {}; const migration = {}
migration.start = async () => { migration.start = async () => {
await db.schema.table('albums', table => { await db.schema.table('albums', table => {
table.dateTime('editedAt'); table.dateTime('editedAt')
table.dateTime('zipGeneratedAt'); table.dateTime('zipGeneratedAt')
}); })
console.log('Migration finished! Now start lolisafe normally'); console.log('Migration finished! Now start lolisafe normally')
}; }
migration.start(); migration.start()

View File

@ -1,58 +1,66 @@
const config = require('./config.js'); const config = require('./config.js')
const api = require('./routes/api.js'); const api = require('./routes/api.js')
const album = require('./routes/album.js'); const album = require('./routes/album.js')
const express = require('express'); const express = require('express')
const helmet = require('helmet'); const helmet = require('helmet')
const bodyParser = require('body-parser'); const bodyParser = require('body-parser')
const RateLimit = require('express-rate-limit'); const RateLimit = require('express-rate-limit')
const db = require('knex')(config.database); const db = require('knex')(config.database)
const fs = require('fs'); const fs = require('fs')
const exphbs = require('express-handlebars'); const exphbs = require('express-handlebars')
const safe = express(); const safe = express()
require('./database/db.js')(db); require('./database/db.js')(db)
fs.existsSync('./pages/custom') || fs.mkdirSync('./pages/custom'); fs.existsSync('./pages/custom') || fs.mkdirSync('./pages/custom')
fs.existsSync(`./${config.logsFolder}`) || fs.mkdirSync(`./${ config.logsFolder}`); fs.existsSync('./' + config.logsFolder) || fs.mkdirSync('./' + config.logsFolder)
fs.existsSync(`./${config.uploads.folder}`) || fs.mkdirSync(`./${config.uploads.folder}`); fs.existsSync('./' + config.uploads.folder) || fs.mkdirSync('./' + config.uploads.folder)
fs.existsSync(`./${config.uploads.folder}/thumbs`) || fs.mkdirSync(`./${config.uploads.folder }/thumbs`); fs.existsSync('./' + config.uploads.folder + '/thumbs') || fs.mkdirSync('./' + config.uploads.folder + '/thumbs')
fs.existsSync(`./${config.uploads.folder }/zips`) || fs.mkdirSync(`./${config.uploads.folder}/zips`); fs.existsSync('./' + config.uploads.folder + '/zips') || fs.mkdirSync('./' + config.uploads.folder + '/zips')
safe.use(helmet()); safe.use(helmet())
safe.set('trust proxy', 1); safe.set('trust proxy', 1)
safe.engine('handlebars', exphbs({ defaultLayout: 'main' })); safe.engine('handlebars', exphbs({ defaultLayout: 'main' }))
safe.set('view engine', 'handlebars'); safe.set('view engine', 'handlebars')
safe.enable('view cache'); safe.enable('view cache')
let limiter = new RateLimit({ windowMs: 5000, max: 2 }); let limiter = new RateLimit({ windowMs: 5000, max: 2 })
safe.use('/api/login/', limiter); safe.use('/api/login/', limiter)
safe.use('/api/register/', limiter); safe.use('/api/register/', limiter)
safe.use(bodyParser.urlencoded({ extended: true })); safe.use(bodyParser.urlencoded({ extended: true }))
safe.use(bodyParser.json()); safe.use(bodyParser.json())
if (config.serveFilesWithNode) { if (config.serveFilesWithNode) {
safe.use('/', express.static(config.uploads.folder)); safe.use('/', express.static(config.uploads.folder))
} }
safe.use('/', express.static('./public')); safe.use('/', express.static('./public'))
safe.use('/', album); safe.use('/', album)
safe.use('/api', api); safe.use('/api', api)
for (let page of config.pages) { for (let page of config.pages) {
let root = './pages/'; let root = './pages/'
if (fs.existsSync(`./pages/custom/${page}.html`)) { if (fs.existsSync(`./pages/custom/${page}.html`)) {
root = './pages/custom/'; root = './pages/custom/'
} }
if (page === 'home') { if (page === 'home') {
safe.get('/', (req, res, next) => res.sendFile(`${page}.html`, { root: root })); safe.get('/', (req, res, next) => res.sendFile(`${page}.html`, { root: root }))
} else { } else {
safe.get(`/${page}`, (req, res, next) => res.sendFile(`${page}.html`, { root: root })); safe.get(`/${page}`, (req, res, next) => res.sendFile(`${page}.html`, { root: root }))
} }
} }
safe.use((req, res, next) => res.status(404).sendFile('404.html', { root: './pages/error/' })); safe.use((req, res, next) => res.status(404).sendFile('404.html', { root: './pages/error/' }))
safe.use((req, res, next) => res.status(500).sendFile('500.html', { root: './pages/error/' })); safe.use((req, res, next) => res.status(500).sendFile('500.html', { root: './pages/error/' }))
safe.listen(config.port, () => console.log(`lolisafe started on port ${config.port}`)); safe.listen(config.port, () => console.log(`lolisafe started on port ${config.port}`))
process.on('uncaughtException', err => {
console.error(`Uncaught Exception:\n${err.stack}`)
})
process.on('unhandledRejection', err => {
console.error(`Unhandled Rejection (Promise):\n${err.stack}`)
})

View File

@ -30,19 +30,9 @@
"sqlite3": "^3.1.13" "sqlite3": "^3.1.13"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^4.4.1", "standard": "^10.0.3"
"eslint-config-aqua": "^1.5.0"
}, },
"eslintConfig": { "standard": {
"extends": [ "envs": ["browser", "node"]
"aqua"
],
"env": {
"browser": true,
"node": true
},
"rules": {
"func-names": 0
}
} }
} }

View File

@ -39,6 +39,7 @@
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js"></script>
<script type="text/javascript" src="https://use.fontawesome.com/cd26baa9bd.js"></script> <script type="text/javascript" src="https://use.fontawesome.com/cd26baa9bd.js"></script>
<script type="text/javascript" src="/js/auth.js"></script> <script type="text/javascript" src="/js/auth.js"></script>
<style type="text/css"> <style type="text/css">
/** Based on KDE Breeze Dark **/ /** Based on KDE Breeze Dark **/
@ -46,6 +47,7 @@
background-color: #232629; background-color: #232629;
} }
</style> </style>
</head> </head>
<body> <body>

View File

@ -39,6 +39,7 @@
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js"></script>
<script type="text/javascript" src="https://use.fontawesome.com/cd26baa9bd.js"></script> <script type="text/javascript" src="https://use.fontawesome.com/cd26baa9bd.js"></script>
<script type="text/javascript" src="/js/dashboard.js"></script> <script type="text/javascript" src="/js/dashboard.js"></script>
<style type="text/css"> <style type="text/css">
/** Based on KDE Breeze Dark **/ /** Based on KDE Breeze Dark **/
@ -122,6 +123,7 @@
border-left-color: #31363b; border-left-color: #31363b;
} }
</style> </style>
</head> </head>
<body> <body>

View File

@ -1,44 +1,56 @@
var page = {}; /* global swal, axios */
page.do = function(dest) { var page = {}
var user = document.getElementById('user').value;
var pass = document.getElementById('pass').value;
if (user === undefined || user === null || user === '') { return swal('Error', 'You need to specify a username', 'error'); } page.do = function (dest) {
if (pass === undefined || pass === null || pass === '') { return swal('Error', 'You need to specify a username', 'error'); } var user = document.getElementById('user').value
var pass = document.getElementById('pass').value
axios.post(`/api/${dest}`, { if (user === undefined || user === null || user === '') {
return swal('Error', 'You need to specify a username', 'error')
}
if (pass === undefined || pass === null || pass === '') {
return swal('Error', 'You need to specify a username', 'error')
}
axios.post('/api/' + dest, {
username: user, username: user,
password: pass password: pass
}) })
.then(response => { .then(function (response) {
if (response.data.success === false) { return swal('Error', response.data.description, 'error'); } if (response.data.success === false) {
return swal('Error', response.data.description, 'error')
}
localStorage.token = response.data.token; localStorage.token = response.data.token
window.location = '/dashboard'; window.location = '/dashboard'
}) })
.catch(error => { .catch(function (error) {
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); console.log(error)
console.log(error); return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
});
};
page.verify = function() {
page.token = localStorage.token;
if (page.token === undefined) return;
axios.post('/api/tokens/verify', { token: page.token })
.then(response => {
if (response.data.success === false) { return swal('Error', response.data.description, 'error'); }
window.location = '/dashboard';
}) })
.catch(error => { }
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error');
console.log(error);
});
};
window.onload = function() { page.verify = function () {
page.verify(); page.token = localStorage.token
}; if (page.token === undefined) return
axios.post('/api/tokens/verify', {
token: page.token
})
.then(function (response) {
if (response.data.success === false) {
return swal('Error', response.data.description, 'error')
}
window.location = '/dashboard'
})
.catch(function (error) {
console.log(error)
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
})
}
window.onload = function () {
page.verify()
}

View File

@ -1,102 +1,112 @@
let panel = {}; /* eslint-disable no-unused-expressions */
/* global swal, axios */
panel.page; let panel = {}
panel.username;
panel.token = localStorage.token;
panel.filesView = localStorage.filesView;
panel.preparePage = function() { panel.page
if (!panel.token) return window.location = '/auth'; panel.username
panel.verifyToken(panel.token, true); panel.token = localStorage.token
}; panel.filesView = localStorage.filesView
panel.verifyToken = function(token, reloadOnError) { panel.preparePage = function () {
if (reloadOnError === undefined) { reloadOnError = false; } if (!panel.token) {
window.location = '/auth'
return '/auth'
}
panel.verifyToken(panel.token, true)
}
axios.post('/api/tokens/verify', { token: token }) panel.verifyToken = function (token, reloadOnError) {
.then(response => { if (reloadOnError === undefined) {
reloadOnError = false
}
axios.post('/api/tokens/verify', {
token: token
})
.then(function (response) {
if (response.data.success === false) { if (response.data.success === false) {
swal({ swal({
title: 'An error ocurred', title: 'An error ocurred',
text: response.data.description, text: response.data.description,
type: 'error' type: 'error'
}, () => { }, function () {
if (reloadOnError) { if (reloadOnError) {
localStorage.removeItem('token'); localStorage.removeItem('token')
location.location = '/auth'; location.location = '/auth'
} }
});
return;
}
axios.defaults.headers.common.token = token;
localStorage.token = token;
panel.token = token;
panel.username = response.data.username;
return panel.prepareDashboard();
}) })
.catch(error => { return
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error');
console.log(error);
});
};
panel.prepareDashboard = function() {
panel.page = document.getElementById('page');
document.getElementById('auth').style.display = 'none';
document.getElementById('dashboard').style.display = 'block';
document.getElementById('itemUploads').addEventListener('click', function() {
panel.setActiveMenu(this);
});
document.getElementById('itemManageGallery').addEventListener('click', function() {
panel.setActiveMenu(this);
});
document.getElementById('itemTokens').addEventListener('click', function() {
panel.setActiveMenu(this);
});
document.getElementById('itemPassword').addEventListener('click', function() {
panel.setActiveMenu(this);
});
document.getElementById('itemLogout').innerHTML = `Logout ( ${panel.username} )`;
panel.getAlbumsSidebar();
};
panel.logout = function() {
localStorage.removeItem('token');
location.reload('/');
};
panel.getUploads = function(album = undefined, page = undefined) {
if (page === undefined) page = 0;
let url = `/api/uploads/${page}`;
if (album !== undefined) { url = `/api/album/${album}/${page}`; }
axios.get(url).then(response => {
if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token);
else return swal('An error ocurred', response.data.description, 'error');
} }
var prevPage = 0; axios.defaults.headers.common.token = token
var nextPage = page + 1; localStorage.token = token
panel.token = token
panel.username = response.data.username
return panel.prepareDashboard()
})
.catch(function (error) {
console.log(error)
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
})
}
if (response.data.files.length < 25) { nextPage = page; } panel.prepareDashboard = function () {
panel.page = document.getElementById('page')
document.getElementById('auth').style.display = 'none'
document.getElementById('dashboard').style.display = 'block'
if (page > 0) prevPage = page - 1; document.getElementById('itemUploads').addEventListener('click', function () {
panel.setActiveMenu(this)
})
panel.page.innerHTML = ''; document.getElementById('itemManageGallery').addEventListener('click', function () {
var container = document.createElement('div'); panel.setActiveMenu(this)
})
document.getElementById('itemTokens').addEventListener('click', function () {
panel.setActiveMenu(this)
})
document.getElementById('itemPassword').addEventListener('click', function () {
panel.setActiveMenu(this)
})
document.getElementById('itemLogout').innerHTML = `Logout ( ${panel.username} )`
panel.getAlbumsSidebar()
}
panel.logout = function () {
localStorage.removeItem('token')
location.reload('/')
}
panel.getUploads = function (album = undefined, page = undefined) {
if (page === undefined) page = 0
let url = '/api/uploads/' + page
if (album !== undefined) { url = '/api/album/' + album + '/' + page }
axios.get(url).then(function (response) {
if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else return swal('An error ocurred', response.data.description, 'error')
}
var prevPage = 0
var nextPage = page + 1
if (response.data.files.length < 25) { nextPage = page }
if (page > 0) prevPage = page - 1
panel.page.innerHTML = ''
var container = document.createElement('div')
var pagination = `<nav class="pagination is-centered"> var pagination = `<nav class="pagination is-centered">
<a class="pagination-previous" onclick="panel.getUploads(${album}, ${prevPage} )">Previous</a> <a class="pagination-previous" onclick="panel.getUploads(${album}, ${prevPage} )">Previous</a>
<a class="pagination-next" onclick="panel.getUploads(${album}, ${nextPage} )">Next page</a> <a class="pagination-next" onclick="panel.getUploads(${album}, ${nextPage} )">Next page</a>
</nav>`; </nav>`
var listType = ` var listType = `
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">
@ -111,8 +121,9 @@ panel.getUploads = function(album = undefined, page = undefined) {
</span> </span>
</a> </a>
</div> </div>
</div>`; </div>`
var table, item
if (panel.filesView === 'thumbs') { if (panel.filesView === 'thumbs') {
container.innerHTML = ` container.innerHTML = `
${pagination} ${pagination}
@ -122,20 +133,24 @@ panel.getUploads = function(album = undefined, page = undefined) {
</div> </div>
${pagination} ${pagination}
`; `
panel.page.appendChild(container); panel.page.appendChild(container)
var table = document.getElementById('table'); table = document.getElementById('table')
for (var item of response.data.files) { for (item of response.data.files) {
var div = document.createElement('div'); var div = document.createElement('div')
div.className = 'column is-2'; div.className = 'column is-2'
if (item.thumb !== undefined) { div.innerHTML = `<a href="${item.file}" target="_blank"><img src="${item.thumb}"/></a>`; } else { div.innerHTML = `<a href="${item.file}" target="_blank"><h1 class="title">.${item.file.split('.').pop()}</h1></a>`; } if (item.thumb !== undefined) {
table.appendChild(div); div.innerHTML = `<a href="${item.file}" target="_blank"><img src="${item.thumb}"/></a>`
} else {
div.innerHTML = `<a href="${item.file}" target="_blank"><h1 class="title">.${item.file.split('.').pop()}</h1></a>`
}
table.appendChild(div)
} }
} else { } else {
var albumOrUser = 'Album'; var albumOrUser = 'Album'
if (panel.username === 'root') { albumOrUser = 'User'; } if (panel.username === 'root') { albumOrUser = 'User' }
container.innerHTML = ` container.innerHTML = `
${pagination} ${pagination}
@ -155,18 +170,19 @@ panel.getUploads = function(album = undefined, page = undefined) {
</table> </table>
<hr> <hr>
${pagination} ${pagination}
`; `
panel.page.appendChild(container); panel.page.appendChild(container)
var table = document.getElementById('table'); table = document.getElementById('table')
for (var item of response.data.files) { for (item of response.data.files) {
var tr = document.createElement('tr'); var tr = document.createElement('tr')
var displayAlbumOrUser = item.album; var displayAlbumOrUser = item.album
console.log(item)
if (panel.username === 'root') { if (panel.username === 'root') {
displayAlbumOrUser = ''; displayAlbumOrUser = ''
if (item.username !== undefined) { displayAlbumOrUser = item.username; } if (item.username !== undefined) { displayAlbumOrUser = item.username }
} }
tr.innerHTML = ` tr.innerHTML = `
@ -182,25 +198,25 @@ panel.getUploads = function(album = undefined, page = undefined) {
</a> </a>
</td> </td>
</tr> </tr>
`; `
table.appendChild(tr); table.appendChild(tr)
} }
} }
}) })
.catch(error => { .catch(function (error) {
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); console.log(error)
console.log(error); return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
}); })
}; }
panel.setFilesView = function(view, album, page) { panel.setFilesView = function (view, album, page) {
localStorage.filesView = view; localStorage.filesView = view
panel.filesView = view; panel.filesView = view
panel.getUploads(album, page); panel.getUploads(album, page)
}; }
panel.deleteFile = function(id) { panel.deleteFile = function (id) {
swal({ swal({
title: 'Are you sure?', title: 'Are you sure?',
text: 'You wont be able to recover the file!', text: 'You wont be able to recover the file!',
@ -210,35 +226,37 @@ panel.deleteFile = function(id) {
confirmButtonText: 'Yes, delete it!', confirmButtonText: 'Yes, delete it!',
closeOnConfirm: false closeOnConfirm: false
}, },
() => { function () {
axios.post('/api/upload/delete', { id: id }) axios.post('/api/upload/delete', {
.then(response => { id: id
if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token);
else return swal('An error ocurred', response.data.description, 'error');
}
swal('Deleted!', 'The file has been deleted.', 'success');
panel.getUploads();
}) })
.catch(error => { .then(function (response) {
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error');
console.log(error);
});
}
);
};
panel.getAlbums = function() {
axios.get('/api/albums').then(response => {
if (response.data.success === false) { if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token); if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else return swal('An error ocurred', response.data.description, 'error'); else return swal('An error ocurred', response.data.description, 'error')
} }
panel.page.innerHTML = ''; swal('Deleted!', 'The file has been deleted.', 'success')
var container = document.createElement('div'); panel.getUploads()
container.className = 'container'; })
.catch(function (error) {
console.log(error)
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
})
}
)
}
panel.getAlbums = function () {
axios.get('/api/albums').then(function (response) {
if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else return swal('An error ocurred', response.data.description, 'error')
}
panel.page.innerHTML = ''
var container = document.createElement('div')
container.className = 'container'
container.innerHTML = ` container.innerHTML = `
<h2 class="subtitle">Create new album</h2> <h2 class="subtitle">Create new album</h2>
@ -261,13 +279,13 @@ panel.getAlbums = function() {
</thead> </thead>
<tbody id="table"> <tbody id="table">
</tbody> </tbody>
</table>`; </table>`
panel.page.appendChild(container); panel.page.appendChild(container)
var table = document.getElementById('table'); var table = document.getElementById('table')
for (var item of response.data.albums) { for (var item of response.data.albums) {
var tr = document.createElement('tr'); var tr = document.createElement('tr')
tr.innerHTML = ` tr.innerHTML = `
<tr> <tr>
<th>${item.name}</th> <th>${item.name}</th>
@ -287,22 +305,22 @@ panel.getAlbums = function() {
</a> </a>
</td> </td>
</tr> </tr>
`; `
table.appendChild(tr); table.appendChild(tr)
} }
document.getElementById('submitAlbum').addEventListener('click', () => { document.getElementById('submitAlbum').addEventListener('click', function () {
panel.submitAlbum(); panel.submitAlbum()
});
}) })
.catch(error => { })
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); .catch(function (error) {
console.log(error); console.log(error)
}); return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
}; })
}
panel.renameAlbum = function(id) { panel.renameAlbum = function (id) {
swal({ swal({
title: 'Rename album', title: 'Rename album',
text: 'New name you want to give the album:', text: 'New name you want to give the album:',
@ -311,37 +329,37 @@ panel.renameAlbum = function(id) {
closeOnConfirm: false, closeOnConfirm: false,
animation: 'slide-from-top', animation: 'slide-from-top',
inputPlaceholder: 'My super album' inputPlaceholder: 'My super album'
}, inputValue => { }, function (inputValue) {
if (inputValue === false) return false; if (inputValue === false) return false
if (inputValue === '') { if (inputValue === '') {
swal.showInputError('You need to write something!'); swal.showInputError('You need to write something!')
return false; return false
} }
axios.post('/api/albums/rename', { axios.post('/api/albums/rename', {
id: id, id: id,
name: inputValue name: inputValue
}) })
.then(response => { .then(function (response) {
if (response.data.success === false) { if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token); if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else if (response.data.description === 'Name already in use') swal.showInputError('That name is already in use!'); else if (response.data.description === 'Name already in use') swal.showInputError('That name is already in use!')
else swal('An error ocurred', response.data.description, 'error'); else swal('An error ocurred', response.data.description, 'error')
return; return
} }
swal('Success!', `Your album was renamed to: ${inputValue}`, 'success'); swal('Success!', 'Your album was renamed to: ' + inputValue, 'success')
panel.getAlbumsSidebar(); panel.getAlbumsSidebar()
panel.getAlbums(); panel.getAlbums()
}) })
.catch(error => { .catch(function (error) {
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); console.log(error)
console.log(error); return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
}); })
}); })
}; }
panel.deleteAlbum = function(id) { panel.deleteAlbum = function (id) {
swal({ swal({
title: 'Are you sure?', title: 'Are you sure?',
text: "This won't delete your files, only the album!", text: "This won't delete your files, only the album!",
@ -351,93 +369,98 @@ panel.deleteAlbum = function(id) {
confirmButtonText: 'Yes, delete it!', confirmButtonText: 'Yes, delete it!',
closeOnConfirm: false closeOnConfirm: false
}, },
() => { function () {
axios.post('/api/albums/delete', { id: id }) axios.post('/api/albums/delete', {
.then(response => { id: id
if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token);
else return swal('An error ocurred', response.data.description, 'error');
}
swal('Deleted!', 'Your album has been deleted.', 'success');
panel.getAlbumsSidebar();
panel.getAlbums();
}) })
.catch(error => { .then(function (response) {
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error');
console.log(error);
});
}
);
};
panel.submitAlbum = function() {
axios.post('/api/albums', { name: document.getElementById('albumName').value })
.then(response => {
if (response.data.success === false) { if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token); if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else return swal('An error ocurred', response.data.description, 'error'); else return swal('An error ocurred', response.data.description, 'error')
} }
swal('Woohoo!', 'Album was added successfully', 'success'); swal('Deleted!', 'Your album has been deleted.', 'success')
panel.getAlbumsSidebar(); panel.getAlbumsSidebar()
panel.getAlbums(); panel.getAlbums()
}) })
.catch(error => { .catch(function (error) {
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); console.log(error)
console.log(error); return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
}); })
}; }
)
}
panel.getAlbumsSidebar = function() { panel.submitAlbum = function () {
axios.post('/api/albums', {
name: document.getElementById('albumName').value
})
.then(function (response) {
if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else return swal('An error ocurred', response.data.description, 'error')
}
swal('Woohoo!', 'Album was added successfully', 'success')
panel.getAlbumsSidebar()
panel.getAlbums()
})
.catch(function (error) {
console.log(error)
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
})
}
panel.getAlbumsSidebar = function () {
axios.get('/api/albums/sidebar') axios.get('/api/albums/sidebar')
.then(response => { .then(function (response) {
if (response.data.success === false) { if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token); if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else return swal('An error ocurred', response.data.description, 'error'); else return swal('An error ocurred', response.data.description, 'error')
} }
var albumsContainer = document.getElementById('albumsContainer'); var albumsContainer = document.getElementById('albumsContainer')
albumsContainer.innerHTML = ''; albumsContainer.innerHTML = ''
if (response.data.albums === undefined) return; if (response.data.albums === undefined) return
var li, a
for (var album of response.data.albums) { for (var album of response.data.albums) {
li = document.createElement('li'); li = document.createElement('li')
a = document.createElement('a'); a = document.createElement('a')
a.id = album.id; a.id = album.id
a.innerHTML = album.name; a.innerHTML = album.name
a.addEventListener('click', function() { a.addEventListener('click', function () {
panel.getAlbum(this); panel.getAlbum(this)
}); })
li.appendChild(a); li.appendChild(a)
albumsContainer.appendChild(li); albumsContainer.appendChild(li)
} }
}) })
.catch(error => { .catch(function (error) {
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); console.log(error)
console.log(error); return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
}); })
}; }
panel.getAlbum = function(item) { panel.getAlbum = function (item) {
panel.setActiveMenu(item); panel.setActiveMenu(item)
panel.getUploads(item.id); panel.getUploads(item.id)
}; }
panel.changeToken = function() { panel.changeToken = function () {
axios.get('/api/tokens') axios.get('/api/tokens')
.then(response => { .then(function (response) {
if (response.data.success === false) { if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token); if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else return swal('An error ocurred', response.data.description, 'error'); else return swal('An error ocurred', response.data.description, 'error')
} }
panel.page.innerHTML = ''; panel.page.innerHTML = ''
var container = document.createElement('div'); var container = document.createElement('div')
container.className = 'container'; container.className = 'container'
container.innerHTML = ` container.innerHTML = `
<h2 class="subtitle">Manage your token</h2> <h2 class="subtitle">Manage your token</h2>
@ -446,47 +469,47 @@ panel.changeToken = function() {
<input id="token" readonly class="input is-expanded" type="text" placeholder="Your token" value="${response.data.token}"> <input id="token" readonly class="input is-expanded" type="text" placeholder="Your token" value="${response.data.token}">
<a id="getNewToken" class="button is-primary">Request new token</a> <a id="getNewToken" class="button is-primary">Request new token</a>
</p> </p>
`; `
panel.page.appendChild(container); panel.page.appendChild(container)
document.getElementById('getNewToken').addEventListener('click', () => { document.getElementById('getNewToken').addEventListener('click', function () {
panel.getNewToken(); panel.getNewToken()
});
}) })
.catch(error => { })
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); .catch(function (error) {
console.log(error); console.log(error)
}); return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
}; })
}
panel.getNewToken = function() { panel.getNewToken = function () {
axios.post('/api/tokens/change') axios.post('/api/tokens/change')
.then(response => { .then(function (response) {
if (response.data.success === false) { if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token); if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else return swal('An error ocurred', response.data.description, 'error'); else return swal('An error ocurred', response.data.description, 'error')
} }
swal({ swal({
title: 'Woohoo!', title: 'Woohoo!',
text: 'Your token was changed successfully.', text: 'Your token was changed successfully.',
type: 'success' type: 'success'
}, () => { }, function () {
localStorage.token = response.data.token; localStorage.token = response.data.token
location.reload(); location.reload()
});
}) })
.catch(error => { })
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); .catch(function (error) {
console.log(error); console.log(error)
}); return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
}; })
}
panel.changePassword = function() { panel.changePassword = function () {
panel.page.innerHTML = ''; panel.page.innerHTML = ''
var container = document.createElement('div'); var container = document.createElement('div')
container.className = 'container'; container.className = 'container'
container.innerHTML = ` container.innerHTML = `
<h2 class="subtitle">Change your password</h2> <h2 class="subtitle">Change your password</h2>
@ -499,55 +522,55 @@ panel.changePassword = function() {
<input id="passwordConfirm" class="input is-expanded" type="password" placeholder="Verify your new password"> <input id="passwordConfirm" class="input is-expanded" type="password" placeholder="Verify your new password">
<a id="sendChangePassword" class="button is-primary">Set new password</a> <a id="sendChangePassword" class="button is-primary">Set new password</a>
</p> </p>
`; `
panel.page.appendChild(container); panel.page.appendChild(container)
document.getElementById('sendChangePassword').addEventListener('click', () => { document.getElementById('sendChangePassword').addEventListener('click', function () {
if (document.getElementById('password').value === document.getElementById('passwordConfirm').value) { if (document.getElementById('password').value === document.getElementById('passwordConfirm').value) {
panel.sendNewPassword(document.getElementById('password').value); panel.sendNewPassword(document.getElementById('password').value)
} else { } else {
swal({ swal({
title: 'Password mismatch!', title: 'Password mismatch!',
text: 'Your passwords do not match, please try again.', text: 'Your passwords do not match, please try again.',
type: 'error' type: 'error'
}, () => { }, function () {
panel.changePassword(); panel.changePassword()
}); })
} }
}); })
}; }
panel.sendNewPassword = function(pass) { panel.sendNewPassword = function (pass) {
axios.post('/api/password/change', { password: pass }) axios.post('/api/password/change', {password: pass})
.then(response => { .then(function (response) {
if (response.data.success === false) { if (response.data.success === false) {
if (response.data.description === 'No token provided') return panel.verifyToken(panel.token); if (response.data.description === 'No token provided') return panel.verifyToken(panel.token)
else return swal('An error ocurred', response.data.description, 'error'); else return swal('An error ocurred', response.data.description, 'error')
} }
swal({ swal({
title: 'Woohoo!', title: 'Woohoo!',
text: 'Your password was changed successfully.', text: 'Your password was changed successfully.',
type: 'success' type: 'success'
}, () => { }, function () {
location.reload(); location.reload()
});
}) })
.catch(error => { })
return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); .catch(function (error) {
console.log(error); console.log(error)
}); return swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
}; })
}
panel.setActiveMenu = function(item) { panel.setActiveMenu = function (item) {
var menu = document.getElementById('menu'); var menu = document.getElementById('menu')
var items = menu.getElementsByTagName('a'); var items = menu.getElementsByTagName('a')
for (var i = 0; i < items.length; i++) { items[i].className = ''; } for (var i = 0; i < items.length; i++) { items[i].className = '' }
item.className = 'is-active'; item.className = 'is-active'
}; }
window.onload = function() { window.onload = function () {
panel.preparePage(); panel.preparePage()
}; }

View File

@ -1,33 +1,39 @@
var upload = {}; /* eslint-disable no-unused-expressions */
/* global swal, axios, Dropzone */
upload.isPrivate = true; var upload = {}
upload.token = localStorage.token;
upload.maxFileSize; upload.isPrivate = true
upload.token = localStorage.token
upload.maxFileSize
// Add the album var to the upload so we can store the album id in there // Add the album var to the upload so we can store the album id in there
upload.album; upload.album
upload.myDropzone; upload.myDropzone
upload.checkIfPublic = function() { upload.checkIfPublic = function () {
axios.get('/api/check') axios.get('/api/check')
.then(response => { .then(response => {
upload.isPrivate = response.data.private; upload.isPrivate = response.data.private
upload.maxFileSize = response.data.maxFileSize; upload.maxFileSize = response.data.maxFileSize
upload.preparePage(); upload.preparePage()
}) })
.catch(error => { .catch(error => {
swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
return console.log(error); return console.log(error)
}); })
}; }
upload.preparePage = function() { upload.preparePage = function () {
if (!upload.isPrivate) return upload.prepareUpload(); if (!upload.isPrivate) return upload.prepareUpload()
if (!upload.token) return document.getElementById('loginToUpload').style.display = 'inline-flex'; if (!upload.token) {
upload.verifyToken(upload.token, true); document.getElementById('loginToUpload').style.display = 'inline-flex'
}; return 'inline-flex'
}
upload.verifyToken(upload.token, true)
}
upload.verifyToken = function(token, reloadOnError) { upload.verifyToken = function (token, reloadOnError) {
if (reloadOnError === undefined) { reloadOnError = false; } if (reloadOnError === undefined) { reloadOnError = false }
axios.post('/api/tokens/verify', { token: token }) axios.post('/api/tokens/verify', { token: token })
.then(response => { .then(response => {
@ -38,76 +44,76 @@ upload.verifyToken = function(token, reloadOnError) {
type: 'error' type: 'error'
}, () => { }, () => {
if (reloadOnError) { if (reloadOnError) {
localStorage.removeItem('token'); localStorage.removeItem('token')
location.reload(); location.reload()
} }
}); })
return; return
} }
localStorage.token = token; localStorage.token = token
upload.token = token; upload.token = token
return upload.prepareUpload(); return upload.prepareUpload()
}) })
.catch(error => { .catch(error => {
swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
return console.log(error); return console.log(error)
}); })
}; }
upload.prepareUpload = function() { upload.prepareUpload = function () {
// I think this fits best here because we need to check for a valid token before we can get the albums // I think this fits best here because we need to check for a valid token before we can get the albums
if (upload.token) { if (upload.token) {
var select = document.getElementById('albumSelect'); var select = document.getElementById('albumSelect')
select.addEventListener('change', () => { select.addEventListener('change', () => {
upload.album = select.value; upload.album = select.value
}); })
axios.get('/api/albums', { headers: { token: upload.token } }) axios.get('/api/albums', { headers: { token: upload.token } })
.then(res => { .then(res => {
var albums = res.data.albums; var albums = res.data.albums
// If the user doesn't have any albums we don't really need to display // If the user doesn't have any albums we don't really need to display
// an album selection // an album selection
if (albums.length === 0) return; if (albums.length === 0) return
// Loop through the albums and create an option for each album // Loop through the albums and create an option for each album
for (var i = 0; i < albums.length; i++) { for (var i = 0; i < albums.length; i++) {
var opt = document.createElement('option'); var opt = document.createElement('option')
opt.value = albums[i].id; opt.value = albums[i].id
opt.innerHTML = albums[i].name; opt.innerHTML = albums[i].name
select.appendChild(opt); select.appendChild(opt)
} }
// Display the album selection // Display the album selection
document.getElementById('albumDiv').style.display = 'block'; document.getElementById('albumDiv').style.display = 'block'
}) })
.catch(e => { .catch(e => {
swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error'); swal('An error ocurred', 'There was an error with the request, please check the console for more information.', 'error')
return console.log(e); return console.log(e)
}); })
} }
div = document.createElement('div'); var div = document.createElement('div')
div.id = 'dropzone'; div.id = 'dropzone'
div.innerHTML = 'Click here or drag and drop files'; div.innerHTML = 'Click here or drag and drop files'
div.style.display = 'flex'; div.style.display = 'flex'
document.getElementById('maxFileSize').innerHTML = `Maximum upload size per file is ${upload.maxFileSize}`; document.getElementById('maxFileSize').innerHTML = `Maximum upload size per file is ${upload.maxFileSize}`
document.getElementById('loginToUpload').style.display = 'none'; document.getElementById('loginToUpload').style.display = 'none'
if (upload.token === undefined) { document.getElementById('loginLinkText').innerHTML = 'Create an account and keep track of your uploads'; } if (upload.token === undefined) { document.getElementById('loginLinkText').innerHTML = 'Create an account and keep track of your uploads' }
document.getElementById('uploadContainer').appendChild(div); document.getElementById('uploadContainer').appendChild(div)
upload.prepareDropzone(); upload.prepareDropzone()
}; }
upload.prepareDropzone = function() { upload.prepareDropzone = function () {
var previewNode = document.querySelector('#template'); var previewNode = document.querySelector('#template')
previewNode.id = ''; previewNode.id = ''
var previewTemplate = previewNode.parentNode.innerHTML; var previewTemplate = previewNode.parentNode.innerHTML
previewNode.parentNode.removeChild(previewNode); previewNode.parentNode.removeChild(previewNode)
var dropzone = new Dropzone('div#dropzone', { var dropzone = new Dropzone('div#dropzone', {
url: '/api/upload', url: '/api/upload',
@ -121,52 +127,52 @@ upload.prepareDropzone = function() {
maxFiles: 1000, maxFiles: 1000,
autoProcessQueue: true, autoProcessQueue: true,
headers: { token: upload.token }, headers: { token: upload.token },
init: function() { init: function () {
upload.myDropzone = this; upload.myDropzone = this
this.on('addedfile', file => { this.on('addedfile', file => {
document.getElementById('uploads').style.display = 'block'; document.getElementById('uploads').style.display = 'block'
}); })
// Add the selected albumid, if an album is selected, as a header // Add the selected albumid, if an album is selected, as a header
this.on('sending', (file, xhr) => { this.on('sending', (file, xhr) => {
if (upload.album) { if (upload.album) {
xhr.setRequestHeader('albumid', upload.album); xhr.setRequestHeader('albumid', upload.album)
} }
}); })
} }
}); })
// Update the total progress bar // Update the total progress bar
dropzone.on('uploadprogress', (file, progress) => { dropzone.on('uploadprogress', (file, progress) => {
file.previewElement.querySelector('.progress').setAttribute('value', progress); file.previewElement.querySelector('.progress').setAttribute('value', progress)
file.previewElement.querySelector('.progress').innerHTML = `${progress}%`; file.previewElement.querySelector('.progress').innerHTML = `${progress}%`
}); })
dropzone.on('success', (file, response) => { dropzone.on('success', (file, response) => {
// Handle the responseText here. For example, add the text to the preview element: // Handle the responseText here. For example, add the text to the preview element:
if (response.success === false) { if (response.success === false) {
var span = document.createElement('span'); var span = document.createElement('span')
span.innerHTML = response.description; span.innerHTML = response.description
file.previewTemplate.querySelector('.link').appendChild(span); file.previewTemplate.querySelector('.link').appendChild(span)
return; return
} }
a = document.createElement('a'); var a = document.createElement('a')
a.href = response.files[0].url; a.href = response.files[0].url
a.target = '_blank'; a.target = '_blank'
a.innerHTML = response.files[0].url; a.innerHTML = response.files[0].url
file.previewTemplate.querySelector('.link').appendChild(a); file.previewTemplate.querySelector('.link').appendChild(a)
file.previewTemplate.querySelector('.progress').style.display = 'none'; file.previewTemplate.querySelector('.progress').style.display = 'none'
}); })
upload.prepareShareX(); upload.prepareShareX()
}; }
upload.prepareShareX = function() { upload.prepareShareX = function () {
if (upload.token) { if (upload.token) {
var sharex_element = document.getElementById('ShareX'); var sharexElement = document.getElementById('ShareX')
var sharex_file = `{\r\n\ var sharexFile = `{\r\n\
"Name": "${location.hostname}",\r\n\ "Name": "${location.hostname}",\r\n\
"DestinationType": "ImageUploader, FileUploader",\r\n\ "DestinationType": "ImageUploader, FileUploader",\r\n\
"RequestType": "POST",\r\n\ "RequestType": "POST",\r\n\
@ -178,30 +184,29 @@ upload.prepareShareX = function() {
"ResponseType": "Text",\r\n\ "ResponseType": "Text",\r\n\
"URL": "$json:files[0].url$",\r\n\ "URL": "$json:files[0].url$",\r\n\
"ThumbnailURL": "$json:files[0].url$"\r\n\ "ThumbnailURL": "$json:files[0].url$"\r\n\
}`; }`
var sharex_blob = new Blob([sharex_file], { type: 'application/octet-binary' }); var sharexBlob = new Blob([sharexFile], { type: 'application/octet-binary' })
sharex_element.setAttribute('href', URL.createObjectURL(sharex_blob)); sharexElement.setAttribute('href', URL.createObjectURL(sharexBlob))
sharex_element.setAttribute('download', `${location.hostname}.sxcu`); sharexElement.setAttribute('download', `${location.hostname}.sxcu`)
} }
}; }
// Handle image paste event // Handle image paste event
window.addEventListener('paste', event => { window.addEventListener('paste', event => {
var items = (event.clipboardData || event.originalEvent.clipboardData).items; var items = (event.clipboardData || event.originalEvent.clipboardData).items
for (index in items) { for (var index in items) {
var item = items[index]; var item = items[index]
if (item.kind === 'file') { if (item.kind === 'file') {
var blob = item.getAsFile(); var blob = item.getAsFile()
console.log(blob.type); console.log(blob.type)
var file = new File([blob], `pasted-image.${blob.type.match(/(?:[^\/]*\/)([^;]*)/)[1]}`); var file = new File([blob], `pasted-image.${blob.type.match(/(?:[^/]*\/)([^;]*)/)[1]}`)
file.type = blob.type; file.type = blob.type
console.log(file); console.log(file)
upload.myDropzone.addFile(file); upload.myDropzone.addFile(file)
} }
} }
}); })
window.onload = function() {
upload.checkIfPublic();
};
window.onload = function () {
upload.checkIfPublic()
}

View File

@ -1,26 +1,26 @@
const config = require('../config.js'); const config = require('../config.js')
const routes = require('express').Router(); const routes = require('express').Router()
const db = require('knex')(config.database); const db = require('knex')(config.database)
const path = require('path'); const path = require('path')
const utils = require('../controllers/utilsController.js'); const utils = require('../controllers/utilsController.js')
routes.get('/a/:identifier', async (req, res, next) => { routes.get('/a/:identifier', async (req, res, next) => {
let identifier = req.params.identifier; let identifier = req.params.identifier
if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' }); if (identifier === undefined) return res.status(401).json({ success: false, description: 'No identifier provided' })
const album = await db.table('albums').where({ identifier, enabled: 1 }).first(); const album = await db.table('albums').where({ identifier, enabled: 1 }).first()
if (!album) return res.status(404).sendFile('404.html', { root: './pages/error/' }); if (!album) return res.status(404).sendFile('404.html', { root: './pages/error/' })
const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC'); const files = await db.table('files').select('name').where('albumid', album.id).orderBy('id', 'DESC')
let thumb = ''; let thumb = ''
const basedomain = config.domain; const basedomain = config.domain
for (let file of files) { for (let file of files) {
file.file = `${basedomain}/${file.name}`; file.file = `${basedomain}/${file.name}`
let ext = path.extname(file.name).toLowerCase(); let ext = path.extname(file.name).toLowerCase()
if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) { if (utils.imageExtensions.includes(ext) || utils.videoExtensions.includes(ext)) {
file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`; file.thumb = `${basedomain}/thumbs/${file.name.slice(0, -ext.length)}.png`
/* /*
If thumbnail for album is still not set, do it. If thumbnail for album is still not set, do it.
@ -29,18 +29,17 @@ routes.get('/a/:identifier', async (req, res, next) => {
*/ */
if (thumb === '') { if (thumb === '') {
thumb = file.thumb; thumb = file.thumb
} }
file.thumb = `<img src="${file.thumb}"/>`; file.thumb = `<img src="${file.thumb}"/>`
} else { } else {
file.thumb = `<h1 class="title">.${ext}</h1>`; file.thumb = `<h1 class="title">.${ext}</h1>`
} }
} }
let enableDownload = false
let enableDownload = false; if (config.uploads.generateZips) enableDownload = true
if (config.uploads.generateZips) enableDownload = true;
return res.render('album', { return res.render('album', {
layout: false, layout: false,
@ -50,7 +49,7 @@ routes.get('/a/:identifier', async (req, res, next) => {
files, files,
identifier, identifier,
enableDownload enableDownload
}); })
}); })
module.exports = routes; module.exports = routes

View File

@ -1,37 +1,37 @@
const config = require('../config.js'); const config = require('../config.js')
const routes = require('express').Router(); const routes = require('express').Router()
const uploadController = require('../controllers/uploadController'); const uploadController = require('../controllers/uploadController')
const albumsController = require('../controllers/albumsController'); const albumsController = require('../controllers/albumsController')
const tokenController = require('../controllers/tokenController'); const tokenController = require('../controllers/tokenController')
const authController = require('../controllers/authController'); const authController = require('../controllers/authController')
routes.get('/check', (req, res, next) => { routes.get('/check', (req, res, next) => {
return res.json({ return res.json({
private: config.private, private: config.private,
maxFileSize: config.uploads.maxSize maxFileSize: config.uploads.maxSize
}); })
}); })
routes.post('/login', (req, res, next) => authController.verify(req, res, next)); routes.post('/login', (req, res, next) => authController.verify(req, res, next))
routes.post('/register', (req, res, next) => authController.register(req, res, next)); routes.post('/register', (req, res, next) => authController.register(req, res, next))
routes.post('/password/change', (req, res, next) => authController.changePassword(req, res, next)); routes.post('/password/change', (req, res, next) => authController.changePassword(req, res, next))
routes.get('/uploads', (req, res, next) => uploadController.list(req, res, next)); routes.get('/uploads', (req, res, next) => uploadController.list(req, res, next))
routes.get('/uploads/:page', (req, res, next) => uploadController.list(req, res, next)); routes.get('/uploads/:page', (req, res, next) => uploadController.list(req, res, next))
routes.post('/upload', (req, res, next) => uploadController.upload(req, res, next)); routes.post('/upload', (req, res, next) => uploadController.upload(req, res, next))
routes.post('/upload/delete', (req, res, next) => uploadController.delete(req, res, next)); routes.post('/upload/delete', (req, res, next) => uploadController.delete(req, res, next))
routes.post('/upload/:albumid', (req, res, next) => uploadController.upload(req, res, next)); routes.post('/upload/:albumid', (req, res, next) => uploadController.upload(req, res, next))
routes.get('/album/get/:identifier', (req, res, next) => albumsController.get(req, res, next)); routes.get('/album/get/:identifier', (req, res, next) => albumsController.get(req, res, next))
routes.get('/album/zip/:identifier', (req, res, next) => albumsController.generateZip(req, res, next)); routes.get('/album/zip/:identifier', (req, res, next) => albumsController.generateZip(req, res, next))
routes.get('/album/:id', (req, res, next) => uploadController.list(req, res, next)); routes.get('/album/:id', (req, res, next) => uploadController.list(req, res, next))
routes.get('/album/:id/:page', (req, res, next) => uploadController.list(req, res, next)); routes.get('/album/:id/:page', (req, res, next) => uploadController.list(req, res, next))
routes.get('/albums', (req, res, next) => albumsController.list(req, res, next)); routes.get('/albums', (req, res, next) => albumsController.list(req, res, next))
routes.get('/albums/:sidebar', (req, res, next) => albumsController.list(req, res, next)); routes.get('/albums/:sidebar', (req, res, next) => albumsController.list(req, res, next))
routes.post('/albums', (req, res, next) => albumsController.create(req, res, next)); routes.post('/albums', (req, res, next) => albumsController.create(req, res, next))
routes.post('/albums/delete', (req, res, next) => albumsController.delete(req, res, next)); routes.post('/albums/delete', (req, res, next) => albumsController.delete(req, res, next))
routes.post('/albums/rename', (req, res, next) => albumsController.rename(req, res, next)); routes.post('/albums/rename', (req, res, next) => albumsController.rename(req, res, next))
routes.get('/albums/test', (req, res, next) => albumsController.test(req, res, next)); routes.get('/albums/test', (req, res, next) => albumsController.test(req, res, next))
routes.get('/tokens', (req, res, next) => tokenController.list(req, res, next)); routes.get('/tokens', (req, res, next) => tokenController.list(req, res, next))
routes.post('/tokens/verify', (req, res, next) => tokenController.verify(req, res, next)); routes.post('/tokens/verify', (req, res, next) => tokenController.verify(req, res, next))
routes.post('/tokens/change', (req, res, next) => tokenController.change(req, res, next)); routes.post('/tokens/change', (req, res, next) => tokenController.change(req, res, next))
module.exports = routes; module.exports = routes

763
yarn.lock

File diff suppressed because it is too large Load Diff