Merge branch 'account-manager' into safe.fiery.me
2
.gitignore
vendored
@ -12,3 +12,5 @@ migrate.js
|
|||||||
yarn.lock
|
yarn.lock
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
public/render/**/original
|
||||||
|
public/render/**/wip
|
||||||
|
@ -204,9 +204,12 @@ albumsController.edit = async (req, res, next) => {
|
|||||||
})
|
})
|
||||||
.first()
|
.first()
|
||||||
|
|
||||||
if (album && (album.id !== id)) {
|
if (!album) {
|
||||||
|
return res.json({ success: false, description: 'Could not get album with the specified ID.' })
|
||||||
|
} else if (album.id !== id) {
|
||||||
return res.json({ success: false, description: 'Name already in use.' })
|
return res.json({ success: false, description: 'Name already in use.' })
|
||||||
} else if (req._old && (album.id === id)) {
|
} else if (req._old && (album.id === id)) {
|
||||||
|
// Old rename API
|
||||||
return res.json({ success: false, description: 'You did not specify a new name.' })
|
return res.json({ success: false, description: 'You did not specify a new name.' })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +269,7 @@ albumsController.rename = async (req, res, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
albumsController.get = async (req, res, next) => {
|
albumsController.get = async (req, res, next) => {
|
||||||
// TODO:
|
// TODO: ... what was i supposed to do here?
|
||||||
const identifier = req.params.identifier
|
const identifier = req.params.identifier
|
||||||
if (identifier === undefined) {
|
if (identifier === undefined) {
|
||||||
return res.status(401).json({ success: false, description: 'No identifier provided.' })
|
return res.status(401).json({ success: false, description: 'No identifier provided.' })
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const bcrypt = require('bcrypt')
|
const bcrypt = require('bcrypt')
|
||||||
const config = require('./../config')
|
const config = require('./../config')
|
||||||
const db = require('knex')(config.database)
|
const db = require('knex')(config.database)
|
||||||
|
const perms = require('./permissionController')
|
||||||
const randomstring = require('randomstring')
|
const randomstring = require('randomstring')
|
||||||
const utils = require('./utilsController')
|
const utils = require('./utilsController')
|
||||||
|
|
||||||
@ -14,7 +15,9 @@ authController.verify = async (req, res, next) => {
|
|||||||
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.' })
|
||||||
|
}
|
||||||
if (user.enabled === false || user.enabled === 0) {
|
if (user.enabled === false || user.enabled === 0) {
|
||||||
return res.json({ success: false, description: 'This account has been disabled.' })
|
return res.json({ success: false, description: 'This account has been disabled.' })
|
||||||
}
|
}
|
||||||
@ -60,7 +63,8 @@ authController.register = async (req, res, next) => {
|
|||||||
username,
|
username,
|
||||||
password: hash,
|
password: hash,
|
||||||
token,
|
token,
|
||||||
enabled: 1
|
enabled: 1,
|
||||||
|
permission: perms.permissions.user
|
||||||
})
|
})
|
||||||
return res.json({ success: true, token })
|
return res.json({ success: true, token })
|
||||||
})
|
})
|
||||||
@ -94,23 +98,43 @@ authController.changePassword = async (req, res, next) => {
|
|||||||
authController.getFileLengthConfig = async (req, res, next) => {
|
authController.getFileLengthConfig = async (req, res, next) => {
|
||||||
const user = await utils.authorize(req, res)
|
const user = await utils.authorize(req, res)
|
||||||
if (!user) { return }
|
if (!user) { return }
|
||||||
return res.json({ success: true, fileLength: user.fileLength, config: config.uploads.fileLength })
|
return res.json({
|
||||||
|
success: true,
|
||||||
|
fileLength: user.fileLength,
|
||||||
|
config: config.uploads.fileLength
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
authController.changeFileLength = async (req, res, next) => {
|
authController.changeFileLength = async (req, res, next) => {
|
||||||
if (config.uploads.fileLength.userChangeable === false) {
|
if (config.uploads.fileLength.userChangeable === false) {
|
||||||
return res.json({ success: false, description: 'Changing file name length is disabled at the moment.' })
|
return res.json({
|
||||||
|
success: false,
|
||||||
|
description: 'Changing file name length is disabled at the moment.'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await utils.authorize(req, res)
|
const user = await utils.authorize(req, res)
|
||||||
if (!user) { return }
|
if (!user) { return }
|
||||||
|
|
||||||
const fileLength = parseInt(req.body.fileLength)
|
const fileLength = parseInt(req.body.fileLength)
|
||||||
if (fileLength === undefined) { return res.json({ success: false, description: 'No file name length provided.' }) }
|
if (fileLength === undefined) {
|
||||||
if (isNaN(fileLength)) { return res.json({ success: false, description: 'File name length is not a valid number.' }) }
|
return res.json({
|
||||||
|
success: false,
|
||||||
|
description: 'No file name length provided.'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (isNaN(fileLength)) {
|
||||||
|
return res.json({
|
||||||
|
success: false,
|
||||||
|
description: 'File name length is not a valid number.'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (fileLength < config.uploads.fileLength.min || fileLength > config.uploads.fileLength.max) {
|
if (fileLength < config.uploads.fileLength.min || fileLength > config.uploads.fileLength.max) {
|
||||||
return res.json({ success: false, description: `File name length must be ${config.uploads.fileLength.min} to ${config.uploads.fileLength.max} characters.` })
|
return res.json({
|
||||||
|
success: false,
|
||||||
|
description: `File name length must be ${config.uploads.fileLength.min} to ${config.uploads.fileLength.max} characters.`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileLength === user.fileLength) {
|
if (fileLength === user.fileLength) {
|
||||||
@ -124,4 +148,108 @@ authController.changeFileLength = async (req, res, next) => {
|
|||||||
return res.json({ success: true })
|
return res.json({ success: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authController.editUser = async (req, res, next) => {
|
||||||
|
const user = await utils.authorize(req, res)
|
||||||
|
if (!user) { return }
|
||||||
|
|
||||||
|
const id = parseInt(req.body.id)
|
||||||
|
if (isNaN(id)) {
|
||||||
|
return res.json({ success: false, description: 'No user specified.' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = await db.table('users')
|
||||||
|
.where('id', id)
|
||||||
|
.first()
|
||||||
|
|
||||||
|
if (!target) {
|
||||||
|
return res.json({ success: false, description: 'Could not get user with the specified ID.' })
|
||||||
|
} else if (!perms.higher(user, target)) {
|
||||||
|
return res.json({ success: false, description: 'The user is in the same or higher group as you.' })
|
||||||
|
} else if (target.username === 'root') {
|
||||||
|
return res.json({ success: false, description: 'Root user may not be edited.' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const username = String(req.body.username)
|
||||||
|
if (username.length < 4 || username.length > 32) {
|
||||||
|
return res.json({ success: false, description: 'Username must have 4-32 characters.' })
|
||||||
|
}
|
||||||
|
|
||||||
|
let permission = req.body.group ? perms.permissions[req.body.group] : target.permission
|
||||||
|
if (typeof permission !== 'number' || permission < 0) { permission = target.permission }
|
||||||
|
|
||||||
|
await db.table('users')
|
||||||
|
.where('id', id)
|
||||||
|
.update({
|
||||||
|
username,
|
||||||
|
enabled: Boolean(req.body.enabled),
|
||||||
|
permission
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!req.body.resetPassword) {
|
||||||
|
return res.json({ success: true, username })
|
||||||
|
}
|
||||||
|
|
||||||
|
const password = randomstring.generate(16)
|
||||||
|
bcrypt.hash(password, 10, async (error, hash) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(error)
|
||||||
|
return res.json({ success: false, description: 'Error generating password hash (╯°□°)╯︵ ┻━┻.' })
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.table('users')
|
||||||
|
.where('id', id)
|
||||||
|
.update('password', hash)
|
||||||
|
|
||||||
|
return res.json({ success: true, password })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
authController.listUsers = async (req, res, next) => {
|
||||||
|
const user = await utils.authorize(req, res)
|
||||||
|
if (!user) { return }
|
||||||
|
|
||||||
|
const isadmin = perms.is(user, 'admin')
|
||||||
|
if (!isadmin) { return res.status(403) }
|
||||||
|
|
||||||
|
let offset = req.params.page
|
||||||
|
if (offset === undefined) { offset = 0 }
|
||||||
|
|
||||||
|
const users = await db.table('users')
|
||||||
|
// .orderBy('id', 'DESC')
|
||||||
|
.limit(25)
|
||||||
|
.offset(25 * offset)
|
||||||
|
.select('id', 'username', 'enabled', 'fileLength', 'permission')
|
||||||
|
|
||||||
|
if (!users.length) { return res.json({ success: true, users }) }
|
||||||
|
|
||||||
|
const userids = []
|
||||||
|
|
||||||
|
for (const user of users) {
|
||||||
|
user.groups = perms.mapPermissions(user)
|
||||||
|
delete user.permission
|
||||||
|
|
||||||
|
userids.push(user.id)
|
||||||
|
user.uploadsCount = 0
|
||||||
|
user.diskUsage = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const maps = {}
|
||||||
|
const uploads = await db.table('files').whereIn('userid', userids)
|
||||||
|
|
||||||
|
for (const upload of uploads) {
|
||||||
|
// This is the fastest method that I can think of
|
||||||
|
if (maps[upload.userid] === undefined) { maps[upload.userid] = { count: 0, size: 0 } }
|
||||||
|
maps[upload.userid].count++
|
||||||
|
maps[upload.userid].size += parseInt(upload.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const user of users) {
|
||||||
|
if (!maps[user.id]) { continue }
|
||||||
|
user.uploadsCount = maps[user.id].count
|
||||||
|
user.diskUsage = maps[user.id].size
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json({ success: true, users })
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = authController
|
module.exports = authController
|
||||||
|
32
controllers/permissionController.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
const permissionController = {}
|
||||||
|
|
||||||
|
permissionController.permissions = {
|
||||||
|
user: 0, // upload & delete own files, create & delete albums
|
||||||
|
moderator: 50, // delete other user's files
|
||||||
|
admin: 80, // manage users (disable accounts) & create moderators
|
||||||
|
superadmin: 100 // create admins
|
||||||
|
// groups will inherit permissions from groups which have lower value
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionController.is = (user, group) => {
|
||||||
|
// root bypass
|
||||||
|
if (user.username === 'root') { return true }
|
||||||
|
const permission = user.permission || 0
|
||||||
|
return permission >= permissionController.permissions[group]
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionController.higher = (user, target) => {
|
||||||
|
const userPermission = user.permission || 0
|
||||||
|
const targetPermission = target.permission || 0
|
||||||
|
return userPermission > targetPermission
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionController.mapPermissions = user => {
|
||||||
|
const map = {}
|
||||||
|
Object.keys(permissionController.permissions).forEach(group => {
|
||||||
|
map[group] = permissionController.is(user, group)
|
||||||
|
})
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = permissionController
|
@ -1,5 +1,6 @@
|
|||||||
const config = require('./../config')
|
const config = require('./../config')
|
||||||
const db = require('knex')(config.database)
|
const db = require('knex')(config.database)
|
||||||
|
const perms = require('./permissionController')
|
||||||
const randomstring = require('randomstring')
|
const randomstring = require('randomstring')
|
||||||
const utils = require('./utilsController')
|
const utils = require('./utilsController')
|
||||||
|
|
||||||
@ -7,17 +8,35 @@ 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.json({ success: true, username: user.username })
|
return res.status(401).json({
|
||||||
|
success: false,
|
||||||
|
description: 'Invalid token.'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
success: true,
|
||||||
|
username: user.username,
|
||||||
|
permissions: perms.mapPermissions(user)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
if (!user) { return }
|
if (!user) { return }
|
||||||
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) => {
|
||||||
@ -30,7 +49,10 @@ tokenController.change = async (req, res, next) => {
|
|||||||
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
|
||||||
|
@ -5,6 +5,7 @@ const fetch = require('node-fetch')
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const multer = require('multer')
|
const multer = require('multer')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const perms = require('./permissionController')
|
||||||
const randomstring = require('randomstring')
|
const randomstring = require('randomstring')
|
||||||
const utils = require('./utilsController')
|
const utils = require('./utilsController')
|
||||||
|
|
||||||
@ -649,6 +650,11 @@ uploadsController.list = async (req, res) => {
|
|||||||
let offset = req.params.page
|
let offset = req.params.page
|
||||||
if (offset === undefined) { offset = 0 }
|
if (offset === undefined) { offset = 0 }
|
||||||
|
|
||||||
|
// Headers is string-only, this seem to be the safest and lightest
|
||||||
|
const all = req.headers.all === '1'
|
||||||
|
const ismoderator = perms.is(user, 'moderator')
|
||||||
|
if (all && !ismoderator) { return res.json(403) }
|
||||||
|
|
||||||
const files = await db.table('files')
|
const files = await db.table('files')
|
||||||
.where(function () {
|
.where(function () {
|
||||||
if (req.params.id === undefined) {
|
if (req.params.id === undefined) {
|
||||||
@ -658,7 +664,9 @@ uploadsController.list = async (req, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.where(function () {
|
.where(function () {
|
||||||
if (user.username !== 'root') { this.where('userid', user.id) }
|
if (!all || !ismoderator) {
|
||||||
|
this.where('userid', user.id)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.orderBy('id', 'DESC')
|
.orderBy('id', 'DESC')
|
||||||
.limit(25)
|
.limit(25)
|
||||||
@ -668,7 +676,7 @@ uploadsController.list = async (req, res) => {
|
|||||||
const albums = await db.table('albums')
|
const albums = await db.table('albums')
|
||||||
.where(function () {
|
.where(function () {
|
||||||
this.where('enabled', 1)
|
this.where('enabled', 1)
|
||||||
if (user.username !== 'root') {
|
if (!all || !ismoderator) {
|
||||||
this.where('userid', user.id)
|
this.where('userid', user.id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -688,8 +696,8 @@ uploadsController.list = async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only push usernames if we are root
|
// Only push usernames if we are a moderator
|
||||||
if (user.username === 'root') {
|
if (all && ismoderator) {
|
||||||
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)
|
||||||
}
|
}
|
||||||
@ -702,13 +710,12 @@ uploadsController.list = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 (!ismoderator) { return res.json({ success: true, files }) }
|
||||||
|
|
||||||
// If we are root but there are no uploads attached to a user, send response
|
// If we are a moderator but there are no uploads attached to a user, send response
|
||||||
if (userids.length === 0) { return res.json({ success: true, files }) }
|
if (userids.length === 0) { return res.json({ success: true, files }) }
|
||||||
|
|
||||||
const users = await db.table('users')
|
const users = await db.table('users').whereIn('id', userids)
|
||||||
.whereIn('id', userids)
|
|
||||||
for (const dbUser of users) {
|
for (const dbUser of users) {
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
if (file.userid === dbUser.id) {
|
if (file.userid === dbUser.id) {
|
||||||
|
@ -5,6 +5,7 @@ const ffmpeg = require('fluent-ffmpeg')
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const gm = require('gm')
|
const gm = require('gm')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const perms = require('./permissionController')
|
||||||
|
|
||||||
const utilsController = {}
|
const utilsController = {}
|
||||||
const uploadsDir = path.join(__dirname, '..', config.uploads.folder)
|
const uploadsDir = path.join(__dirname, '..', config.uploads.folder)
|
||||||
@ -57,9 +58,18 @@ utilsController.authorize = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const user = await db.table('users').where('token', token).first()
|
const user = await db.table('users').where('token', token).first()
|
||||||
if (user) { return user }
|
if (user) {
|
||||||
|
if (user.enabled === false || user.enabled === 0) {
|
||||||
|
res.json({ success: false, description: 'This account has been disabled.' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
res.status(401).json({ success: false, description: 'Invalid token.' })
|
res.status(401).json({
|
||||||
|
success: false,
|
||||||
|
description: 'Invalid token.'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
utilsController.generateThumbs = (name, force) => {
|
utilsController.generateThumbs = (name, force) => {
|
||||||
@ -158,10 +168,11 @@ utilsController.deleteFile = file => {
|
|||||||
utilsController.bulkDeleteFiles = async (field, values, user) => {
|
utilsController.bulkDeleteFiles = async (field, values, user) => {
|
||||||
if (!user || !['id', 'name'].includes(field)) { return }
|
if (!user || !['id', 'name'].includes(field)) { return }
|
||||||
|
|
||||||
|
const ismoderator = perms.is(user, 'moderator')
|
||||||
const files = await db.table('files')
|
const files = await db.table('files')
|
||||||
.whereIn(field, values)
|
.whereIn(field, values)
|
||||||
.where(function () {
|
.where(function () {
|
||||||
if (user.username !== 'root') {
|
if (!ismoderator) {
|
||||||
this.where('userid', user.id)
|
this.where('userid', user.id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
const perms = require('./../controllers/permissionController')
|
||||||
|
|
||||||
const init = function (db) {
|
const 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.hasTable('albums').then(exists => {
|
db.schema.hasTable('albums').then(exists => {
|
||||||
@ -44,6 +46,7 @@ const init = function (db) {
|
|||||||
table.integer('enabled')
|
table.integer('enabled')
|
||||||
table.integer('timestamp')
|
table.integer('timestamp')
|
||||||
table.integer('fileLength')
|
table.integer('fileLength')
|
||||||
|
table.integer('permission')
|
||||||
}).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 }
|
||||||
@ -55,7 +58,8 @@ const init = function (db) {
|
|||||||
username: 'root',
|
username: 'root',
|
||||||
password: hash,
|
password: hash,
|
||||||
token: require('randomstring').generate(64),
|
token: require('randomstring').generate(64),
|
||||||
timestamp: Math.floor(Date.now() / 1000)
|
timestamp: Math.floor(Date.now() / 1000),
|
||||||
|
permission: perms.permissions.superadmin
|
||||||
}).then(() => {})
|
}).then(() => {})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const config = require('./../config')
|
const config = require('./../config')
|
||||||
const db = require('knex')(config.database)
|
const db = require('knex')(config.database)
|
||||||
|
const perms = require('./../controllers/permissionController')
|
||||||
|
|
||||||
const map = {
|
const map = {
|
||||||
albums: {
|
albums: {
|
||||||
@ -10,7 +11,8 @@ const map = {
|
|||||||
},
|
},
|
||||||
users: {
|
users: {
|
||||||
enabled: 'integer',
|
enabled: 'integer',
|
||||||
fileLength: 'integer'
|
fileLength: 'integer',
|
||||||
|
permission: 'integer'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +32,17 @@ migration.start = async () => {
|
|||||||
}))
|
}))
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
await db.table('users')
|
||||||
|
.where('username', 'root')
|
||||||
|
.first()
|
||||||
|
.update({
|
||||||
|
permission: perms.permissions.superadmin
|
||||||
|
})
|
||||||
|
.then(rows => {
|
||||||
|
if (!rows) { return console.log('Unable to update root\'s permission into superadmin.') }
|
||||||
|
console.log(`Updated root's permission to ${perms.permissions.superadmin} (superadmin).`)
|
||||||
|
})
|
||||||
|
|
||||||
console.log('Migration finished! Now start lolisafe normally')
|
console.log('Migration finished! Now start lolisafe normally')
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
|
13
lolisafe.js
@ -32,9 +32,12 @@ fs.existsSync(`./${config.uploads.folder}/zips`) || fs.mkdirSync(`./${config.upl
|
|||||||
safe.use(helmet())
|
safe.use(helmet())
|
||||||
safe.set('trust proxy', 1)
|
safe.set('trust proxy', 1)
|
||||||
|
|
||||||
|
// https://mozilla.github.io/nunjucks/api.html#configure
|
||||||
nunjucks.configure('views', {
|
nunjucks.configure('views', {
|
||||||
autoescape: true,
|
autoescape: true,
|
||||||
express: safe
|
express: safe,
|
||||||
|
// watch: true, // will this be fine in production?
|
||||||
|
noCache: process.env.DEV === '1'
|
||||||
})
|
})
|
||||||
safe.set('view engine', 'njk')
|
safe.set('view engine', 'njk')
|
||||||
safe.enable('view cache')
|
safe.enable('view cache')
|
||||||
@ -127,7 +130,13 @@ const start = async () => {
|
|||||||
if (!created) { return process.exit(1) }
|
if (!created) { return process.exit(1) }
|
||||||
}
|
}
|
||||||
|
|
||||||
safe.listen(config.port, () => console.log(`lolisafe started on port ${config.port}`))
|
safe.listen(config.port, () => {
|
||||||
|
console.log(`lolisafe started on port ${config.port}`)
|
||||||
|
if (process.env.DEV === '1') {
|
||||||
|
// DEV=1 yarn start
|
||||||
|
console.log('lolisafe is in development mode, nunjucks caching disabled')
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
start()
|
start()
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
.menu-list a {
|
.menu-list a {
|
||||||
color: #3794d2;
|
color: #3794d2;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-list a:hover {
|
.menu-list a:hover {
|
||||||
@ -21,6 +26,15 @@
|
|||||||
background-color: #3794d2;
|
background-color: #3794d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-list a[disabled] {
|
||||||
|
color: #7a7a7a;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-list a[disabled]:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
.pagination a {
|
.pagination a {
|
||||||
color: #eff0f1;
|
color: #eff0f1;
|
||||||
border-color: #4d4d4d;
|
border-color: #4d4d4d;
|
||||||
@ -71,7 +85,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-container .file-checkbox {
|
.image-container .checkbox {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: .75rem;
|
top: .75rem;
|
||||||
left: .75rem;
|
left: .75rem;
|
||||||
@ -118,7 +132,7 @@
|
|||||||
|
|
||||||
/* Make extra info appear on hover only on non-touch devices */
|
/* Make extra info appear on hover only on non-touch devices */
|
||||||
|
|
||||||
.no-touch .image-container .file-checkbox {
|
.no-touch .image-container .checkbox {
|
||||||
opacity: .25;
|
opacity: .25;
|
||||||
-webkit-transition: opacity .25s;
|
-webkit-transition: opacity .25s;
|
||||||
transition: opacity .25s;
|
transition: opacity .25s;
|
||||||
@ -131,7 +145,7 @@
|
|||||||
transition: opacity .25s;
|
transition: opacity .25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-touch .image-container:hover .file-checkbox,
|
.no-touch .image-container:hover .checkbox,
|
||||||
.no-touch .image-container:hover .controls,
|
.no-touch .image-container:hover .controls,
|
||||||
.no-touch .image-container:hover .details {
|
.no-touch .image-container:hover .details {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@ -180,6 +194,6 @@
|
|||||||
height: 2.25em;
|
height: 2.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table td a:not([href]) {
|
.is-linethrough {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,10 @@ a {
|
|||||||
color: #3794d2;
|
color: #3794d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.is-dotted {
|
||||||
|
border-bottom: 1px dotted #3794d2;
|
||||||
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
color: #60a8dc;
|
color: #60a8dc;
|
||||||
}
|
}
|
||||||
@ -96,3 +100,24 @@ hr {
|
|||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.render {
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #bdc3c7;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.render.button {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
right: 1%;
|
||||||
|
opacity: .25;
|
||||||
|
transition: opacity .25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.render.button:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
@ -2,11 +2,24 @@
|
|||||||
background-color: #31363b;
|
background-color: #31363b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.swal-modal .field {
|
||||||
|
text-align: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swal-modal.is-expanded {
|
||||||
|
width: auto;
|
||||||
|
max-width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
.swal-title,
|
.swal-title,
|
||||||
.swal-text {
|
.swal-text {
|
||||||
color: #eff0f1;
|
color: #eff0f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.swal-text {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.swal-content .label,
|
.swal-content .label,
|
||||||
.swal-content .checkbox,
|
.swal-content .checkbox,
|
||||||
.swal-content .radio {
|
.swal-content .radio {
|
||||||
@ -18,6 +31,13 @@
|
|||||||
color: #bdc3c7;
|
color: #bdc3c7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.swal-content .is-code {
|
||||||
|
font-family: 'Courier New', Courier, monospace;
|
||||||
|
border: 1px dashed #eff0f1;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.swal-button {
|
.swal-button {
|
||||||
background-color: #3794d2;
|
background-color: #3794d2;
|
||||||
color: #eff0f1;
|
color: #eff0f1;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 5
|
"ecmaVersion": 6
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true
|
"browser": true
|
||||||
@ -17,6 +17,17 @@
|
|||||||
"quotes": [
|
"quotes": [
|
||||||
"error",
|
"error",
|
||||||
"single"
|
"single"
|
||||||
|
],
|
||||||
|
"object-shorthand": [
|
||||||
|
"error",
|
||||||
|
"always"
|
||||||
|
],
|
||||||
|
"prefer-const": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"destructuring": "any",
|
||||||
|
"ignoreReadBeforeAssign": false
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* global LazyLoad */
|
/* global LazyLoad */
|
||||||
|
|
||||||
var page = {
|
const page = {
|
||||||
lazyLoad: null,
|
lazyLoad: null,
|
||||||
|
|
||||||
// byte units for getPrettyBytes()
|
// byte units for getPrettyBytes()
|
||||||
@ -12,20 +12,20 @@ page.getPrettyBytes = num => {
|
|||||||
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||||
if (!Number.isFinite(num)) { return num }
|
if (!Number.isFinite(num)) { return num }
|
||||||
|
|
||||||
var neg = num < 0
|
const neg = num < 0
|
||||||
if (neg) { num = -num }
|
if (neg) { num = -num }
|
||||||
if (num < 1) { return (neg ? '-' : '') + num + ' B' }
|
if (num < 1) { return (neg ? '-' : '') + num + ' B' }
|
||||||
|
|
||||||
var exponent = Math.min(Math.floor(Math.log10(num) / 3), page.byteUnits.length - 1)
|
const exponent = Math.min(Math.floor(Math.log10(num) / 3), page.byteUnits.length - 1)
|
||||||
var numStr = Number((num / Math.pow(1000, exponent)).toPrecision(3))
|
const numStr = Number((num / Math.pow(1000, exponent)).toPrecision(3))
|
||||||
var unit = page.byteUnits[exponent]
|
const unit = page.byteUnits[exponent]
|
||||||
|
|
||||||
return (neg ? '-' : '') + numStr + ' ' + unit
|
return (neg ? '-' : '') + numStr + ' ' + unit
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
var elements = document.getElementsByClassName('file-size')
|
const elements = document.getElementsByClassName('file-size')
|
||||||
for (var i = 0; i < elements.length; i++) {
|
for (let i = 0; i < elements.length; i++) {
|
||||||
elements[i].innerHTML = page.getPrettyBytes(parseInt(elements[i].innerHTML))
|
elements[i].innerHTML = page.getPrettyBytes(parseInt(elements[i].innerHTML))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* global swal, axios */
|
/* global swal, axios */
|
||||||
|
|
||||||
var page = {
|
const page = {
|
||||||
// user token
|
// user token
|
||||||
token: localStorage.token,
|
token: localStorage.token,
|
||||||
|
|
||||||
@ -10,33 +10,31 @@ var page = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
page.do = function (dest) {
|
page.do = function (dest) {
|
||||||
var user = page.user.value
|
const user = page.user.value
|
||||||
var pass = page.pass.value
|
const pass = page.pass.value
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return swal('Error', 'You need to specify a username', 'error')
|
return swal('An error occurred!', 'You need to specify a username', 'error')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pass) {
|
if (!pass) {
|
||||||
return swal('Error', 'You need to specify a username', 'error')
|
return swal('An error occurred!', 'You need to specify a username', 'error')
|
||||||
}
|
}
|
||||||
|
|
||||||
axios.post('api/' + dest, {
|
axios.post(`api/${dest}`, {
|
||||||
username: user,
|
username: user,
|
||||||
password: pass
|
password: pass
|
||||||
})
|
}).then(function (response) {
|
||||||
.then(function (response) {
|
if (response.data.success === false) {
|
||||||
if (response.data.success === false) {
|
return swal('An error occurred!', response.data.description, 'error')
|
||||||
return swal('Error', response.data.description, 'error')
|
}
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.token = response.data.token
|
localStorage.token = response.data.token
|
||||||
window.location = 'dashboard'
|
window.location = 'dashboard'
|
||||||
})
|
}).catch(function (error) {
|
||||||
.catch(function (error) {
|
console.error(error)
|
||||||
console.error(error)
|
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
||||||
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
page.verify = function () {
|
page.verify = function () {
|
||||||
@ -44,18 +42,16 @@ page.verify = function () {
|
|||||||
|
|
||||||
axios.post('api/tokens/verify', {
|
axios.post('api/tokens/verify', {
|
||||||
token: page.token
|
token: page.token
|
||||||
})
|
}).then(function (response) {
|
||||||
.then(function (response) {
|
if (response.data.success === false) {
|
||||||
if (response.data.success === false) {
|
return swal('An error occurred!', response.data.description, 'error')
|
||||||
return swal('Error', response.data.description, 'error')
|
}
|
||||||
}
|
|
||||||
|
|
||||||
window.location = 'dashboard'
|
window.location = 'dashboard'
|
||||||
})
|
}).catch(function (error) {
|
||||||
.catch(function (error) {
|
console.error(error)
|
||||||
console.error(error)
|
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
||||||
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* global swal, axios, Dropzone, ClipboardJS, LazyLoad */
|
/* global swal, axios, Dropzone, ClipboardJS, LazyLoad */
|
||||||
|
|
||||||
var page = {
|
const page = {
|
||||||
// user token
|
// user token
|
||||||
token: localStorage.token,
|
token: localStorage.token,
|
||||||
|
|
||||||
@ -18,27 +18,25 @@ var page = {
|
|||||||
|
|
||||||
dropzone: null,
|
dropzone: null,
|
||||||
clipboardJS: null,
|
clipboardJS: null,
|
||||||
lazyLoad: null
|
lazyLoad: null,
|
||||||
|
|
||||||
|
imageExtensions: ['.webp', '.jpg', '.jpeg', '.bmp', '.gif', '.png']
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageExtensions = ['.webp', '.jpg', '.jpeg', '.bmp', '.gif', '.png']
|
|
||||||
|
|
||||||
page.checkIfPublic = function () {
|
page.checkIfPublic = function () {
|
||||||
axios.get('api/check')
|
axios.get('api/check').then(function (response) {
|
||||||
.then(function (response) {
|
page.private = response.data.private
|
||||||
page.private = response.data.private
|
page.enableUserAccounts = response.data.enableUserAccounts
|
||||||
page.enableUserAccounts = response.data.enableUserAccounts
|
page.maxFileSize = response.data.maxFileSize
|
||||||
page.maxFileSize = response.data.maxFileSize
|
page.chunkSize = response.data.chunkSize
|
||||||
page.chunkSize = response.data.chunkSize
|
page.preparePage()
|
||||||
page.preparePage()
|
}).catch(function (error) {
|
||||||
})
|
console.log(error)
|
||||||
.catch(function (error) {
|
const button = document.getElementById('loginToUpload')
|
||||||
console.log(error)
|
button.classList.remove('is-loading')
|
||||||
var button = document.getElementById('loginToUpload')
|
button.innerText = 'Error occurred. Reload the page?'
|
||||||
button.classList.remove('is-loading')
|
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
||||||
button.innerText = 'Error occurred. Reload the page?'
|
})
|
||||||
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
page.preparePage = function () {
|
page.preparePage = function () {
|
||||||
@ -46,7 +44,7 @@ page.preparePage = function () {
|
|||||||
if (page.token) {
|
if (page.token) {
|
||||||
return page.verifyToken(page.token, true)
|
return page.verifyToken(page.token, true)
|
||||||
} else {
|
} else {
|
||||||
var button = document.getElementById('loginToUpload')
|
const button = document.getElementById('loginToUpload')
|
||||||
button.href = 'auth'
|
button.href = 'auth'
|
||||||
button.classList.remove('is-loading')
|
button.classList.remove('is-loading')
|
||||||
|
|
||||||
@ -64,29 +62,26 @@ page.preparePage = function () {
|
|||||||
page.verifyToken = function (token, reloadOnError) {
|
page.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 }).then(function (response) {
|
||||||
.then(function (response) {
|
if (response.data.success === false) {
|
||||||
if (response.data.success === false) {
|
return swal({
|
||||||
return swal({
|
title: 'An error occurred!',
|
||||||
title: 'An error occurred!',
|
text: response.data.description,
|
||||||
text: response.data.description,
|
icon: 'error'
|
||||||
icon: 'error'
|
}).then(function () {
|
||||||
})
|
if (!reloadOnError) { return }
|
||||||
.then(function () {
|
localStorage.removeItem('token')
|
||||||
if (!reloadOnError) { return }
|
location.reload()
|
||||||
localStorage.removeItem('token')
|
})
|
||||||
location.reload()
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.token = token
|
localStorage.token = token
|
||||||
page.token = token
|
page.token = token
|
||||||
return page.prepareUpload()
|
return page.prepareUpload()
|
||||||
})
|
}).catch(function (error) {
|
||||||
.catch(function (error) {
|
console.log(error)
|
||||||
console.log(error)
|
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
||||||
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
page.prepareUpload = function () {
|
page.prepareUpload = function () {
|
||||||
@ -104,24 +99,24 @@ page.prepareUpload = function () {
|
|||||||
document.getElementById('albumDiv').style.display = 'flex'
|
document.getElementById('albumDiv').style.display = 'flex'
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('maxFileSize').innerHTML = 'Maximum upload size per file is ' + page.maxFileSize
|
document.getElementById('maxFileSize').innerHTML = `Maximum upload size per file is ${page.maxFileSize}`
|
||||||
document.getElementById('loginToUpload').style.display = 'none'
|
document.getElementById('loginToUpload').style.display = 'none'
|
||||||
|
|
||||||
if (!page.token && page.enableUserAccounts) {
|
if (!page.token && page.enableUserAccounts) {
|
||||||
document.getElementById('loginLinkText').innerHTML = 'Create an account and keep track of your uploads'
|
document.getElementById('loginLinkText').innerHTML = 'Create an account and keep track of your uploads'
|
||||||
}
|
}
|
||||||
|
|
||||||
var previewNode = document.querySelector('#tpl')
|
const previewNode = document.querySelector('#tpl')
|
||||||
page.previewTemplate = previewNode.innerHTML
|
page.previewTemplate = previewNode.innerHTML
|
||||||
previewNode.parentNode.removeChild(previewNode)
|
previewNode.parentNode.removeChild(previewNode)
|
||||||
|
|
||||||
page.prepareDropzone()
|
page.prepareDropzone()
|
||||||
|
|
||||||
var tabs = document.getElementById('tabs')
|
const tabs = document.getElementById('tabs')
|
||||||
if (tabs) {
|
if (tabs) {
|
||||||
tabs.style.display = 'flex'
|
tabs.style.display = 'flex'
|
||||||
var items = tabs.getElementsByTagName('li')
|
const items = tabs.getElementsByTagName('li')
|
||||||
for (var i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
items[i].addEventListener('click', function () {
|
items[i].addEventListener('click', function () {
|
||||||
page.setActiveTab(this.dataset.id)
|
page.setActiveTab(this.dataset.id)
|
||||||
})
|
})
|
||||||
@ -136,42 +131,44 @@ page.prepareUpload = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
page.prepareAlbums = function () {
|
page.prepareAlbums = function () {
|
||||||
var option = document.createElement('option')
|
const option = document.createElement('option')
|
||||||
option.value = ''
|
option.value = ''
|
||||||
option.innerHTML = 'Upload to album'
|
option.innerHTML = 'Upload to album'
|
||||||
option.disabled = true
|
option.disabled = true
|
||||||
option.selected = true
|
option.selected = true
|
||||||
page.albumSelect.appendChild(option)
|
page.albumSelect.appendChild(option)
|
||||||
|
|
||||||
axios.get('api/albums', { headers: { token: page.token } })
|
axios.get('api/albums', {
|
||||||
.then(function (response) {
|
headers: {
|
||||||
if (response.data.success === false) {
|
token: page.token
|
||||||
return swal('An error occurred!', response.data.description, 'error')
|
}
|
||||||
}
|
}).then(function (response) {
|
||||||
|
if (response.data.success === false) {
|
||||||
|
return swal('An error occurred!', response.data.description, 'error')
|
||||||
|
}
|
||||||
|
|
||||||
// If the user doesn't have any albums we don't really need to display
|
// If the user doesn't have any albums we don't really need to display
|
||||||
// an album selection
|
// an album selection
|
||||||
if (!response.data.albums.length) { return }
|
if (!response.data.albums.length) { return }
|
||||||
|
|
||||||
// Loop through the albums and create an option for each album
|
// Loop through the albums and create an option for each album
|
||||||
for (var i = 0; i < response.data.albums.length; i++) {
|
for (let i = 0; i < response.data.albums.length; i++) {
|
||||||
var album = response.data.albums[i]
|
const album = response.data.albums[i]
|
||||||
var option = document.createElement('option')
|
const option = document.createElement('option')
|
||||||
option.value = album.id
|
option.value = album.id
|
||||||
option.innerHTML = album.name
|
option.innerHTML = album.name
|
||||||
page.albumSelect.appendChild(option)
|
page.albumSelect.appendChild(option)
|
||||||
}
|
}
|
||||||
})
|
}).catch(function (error) {
|
||||||
.catch(function (error) {
|
console.log(error)
|
||||||
console.log(error)
|
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
||||||
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
page.setActiveTab = function (activeId) {
|
page.setActiveTab = function (activeId) {
|
||||||
var items = document.getElementById('tabs').getElementsByTagName('li')
|
const items = document.getElementById('tabs').getElementsByTagName('li')
|
||||||
for (var i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
var tabId = items[i].dataset.id
|
const tabId = items[i].dataset.id
|
||||||
if (tabId === activeId) {
|
if (tabId === activeId) {
|
||||||
items[i].classList.add('is-active')
|
items[i].classList.add('is-active')
|
||||||
document.getElementById(tabId).style.display = 'block'
|
document.getElementById(tabId).style.display = 'block'
|
||||||
@ -183,27 +180,27 @@ page.setActiveTab = function (activeId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
page.prepareDropzone = function () {
|
page.prepareDropzone = function () {
|
||||||
var tabDiv = document.getElementById('tab-files')
|
const tabDiv = document.getElementById('tab-files')
|
||||||
var div = document.createElement('div')
|
const div = document.createElement('div')
|
||||||
div.className = 'control is-expanded'
|
div.className = 'control is-expanded'
|
||||||
div.innerHTML =
|
div.innerHTML = `
|
||||||
'<div id="dropzone" class="button is-danger is-fullwidth is-unselectable">\n' +
|
<div id="dropzone" class="button is-danger is-fullwidth is-unselectable">
|
||||||
' <span class="icon">\n' +
|
<span class="icon">
|
||||||
' <i class="icon-upload-cloud"></i>\n' +
|
<i class="icon-upload-cloud"></i>
|
||||||
' </span>\n' +
|
</span>
|
||||||
' <span>Click here or drag and drop files</span>\n' +
|
<span>Click here or drag and drop files</span>
|
||||||
'</div>'
|
</div>
|
||||||
|
`
|
||||||
|
tabDiv.querySelector('.dz-container').appendChild(div)
|
||||||
|
|
||||||
tabDiv.getElementsByClassName('dz-container')[0].appendChild(div)
|
const previewsContainer = tabDiv.querySelector('#tab-files .field.uploads')
|
||||||
|
|
||||||
var previewsContainer = tabDiv.getElementsByClassName('uploads')[0]
|
|
||||||
page.dropzone = new Dropzone('#dropzone', {
|
page.dropzone = new Dropzone('#dropzone', {
|
||||||
url: 'api/upload',
|
url: 'api/upload',
|
||||||
paramName: 'files[]',
|
paramName: 'files[]',
|
||||||
maxFilesize: parseInt(page.maxFileSize),
|
maxFilesize: parseInt(page.maxFileSize),
|
||||||
parallelUploads: 2,
|
parallelUploads: 2,
|
||||||
uploadMultiple: false,
|
uploadMultiple: false,
|
||||||
previewsContainer: previewsContainer,
|
previewsContainer,
|
||||||
previewTemplate: page.previewTemplate,
|
previewTemplate: page.previewTemplate,
|
||||||
createImageThumbnails: false,
|
createImageThumbnails: false,
|
||||||
maxFiles: 1000,
|
maxFiles: 1000,
|
||||||
@ -212,45 +209,41 @@ page.prepareDropzone = function () {
|
|||||||
chunking: Boolean(page.chunkSize),
|
chunking: Boolean(page.chunkSize),
|
||||||
chunkSize: parseInt(page.chunkSize) * 1000000, // 1000000 B = 1 MB,
|
chunkSize: parseInt(page.chunkSize) * 1000000, // 1000000 B = 1 MB,
|
||||||
parallelChunkUploads: false, // when set to true, sometimes it often hangs with hundreds of parallel uploads
|
parallelChunkUploads: false, // when set to true, sometimes it often hangs with hundreds of parallel uploads
|
||||||
chunksUploaded: function (file, done) {
|
chunksUploaded (file, done) {
|
||||||
file.previewElement.querySelector('.progress').setAttribute('value', 100)
|
file.previewElement.querySelector('.progress').setAttribute('value', 100)
|
||||||
file.previewElement.querySelector('.progress').innerHTML = '100%'
|
file.previewElement.querySelector('.progress').innerHTML = '100%'
|
||||||
|
|
||||||
// The API supports an array of multiple files
|
return axios.post('api/upload/finishchunks', {
|
||||||
return axios.post('api/upload/finishchunks',
|
// The API supports an array of multiple files
|
||||||
{
|
files: [{
|
||||||
files: [{
|
uuid: file.upload.uuid,
|
||||||
uuid: file.upload.uuid,
|
original: file.name,
|
||||||
original: file.name,
|
size: file.size,
|
||||||
size: file.size,
|
type: file.type,
|
||||||
type: file.type,
|
count: file.upload.totalChunkCount,
|
||||||
count: file.upload.totalChunkCount,
|
albumid: page.album
|
||||||
albumid: page.album
|
}]
|
||||||
}]
|
}, {
|
||||||
},
|
headers: {
|
||||||
{
|
token: page.token
|
||||||
headers: {
|
}
|
||||||
token: page.token
|
}).then(function (response) {
|
||||||
}
|
file.previewElement.querySelector('.progress').style.display = 'none'
|
||||||
})
|
|
||||||
.then(function (response) {
|
|
||||||
file.previewElement.querySelector('.progress').style.display = 'none'
|
|
||||||
|
|
||||||
if (response.data.success === false) {
|
if (response.data.success === false) {
|
||||||
file.previewElement.querySelector('.error').innerHTML = response.data.description
|
file.previewElement.querySelector('.error').innerHTML = response.data.description
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.data.files && response.data.files[0]) {
|
if (response.data.files && response.data.files[0]) {
|
||||||
page.updateTemplate(file, response.data.files[0])
|
page.updateTemplate(file, response.data.files[0])
|
||||||
}
|
}
|
||||||
return done()
|
return done()
|
||||||
})
|
}).catch(function (error) {
|
||||||
.catch(function (error) {
|
return {
|
||||||
return {
|
success: false,
|
||||||
success: false,
|
description: error.toString()
|
||||||
description: error.toString()
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -269,7 +262,7 @@ page.prepareDropzone = function () {
|
|||||||
page.dropzone.on('uploadprogress', function (file, progress) {
|
page.dropzone.on('uploadprogress', function (file, progress) {
|
||||||
if (file.upload.chunked && progress === 100) { return }
|
if (file.upload.chunked && progress === 100) { return }
|
||||||
file.previewElement.querySelector('.progress').setAttribute('value', progress)
|
file.previewElement.querySelector('.progress').setAttribute('value', progress)
|
||||||
file.previewElement.querySelector('.progress').innerHTML = progress + '%'
|
file.previewElement.querySelector('.progress').innerHTML = `${progress}%`
|
||||||
})
|
})
|
||||||
|
|
||||||
page.dropzone.on('success', function (file, response) {
|
page.dropzone.on('success', function (file, response) {
|
||||||
@ -296,7 +289,7 @@ page.prepareDropzone = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
page.uploadUrls = function (button) {
|
page.uploadUrls = function (button) {
|
||||||
var tabDiv = document.getElementById('tab-urls')
|
const tabDiv = document.getElementById('tab-urls')
|
||||||
if (!tabDiv) { return }
|
if (!tabDiv) { return }
|
||||||
|
|
||||||
if (button.classList.contains('is-loading')) { return }
|
if (button.classList.contains('is-loading')) { return }
|
||||||
@ -308,9 +301,9 @@ page.uploadUrls = function (button) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function run () {
|
function run () {
|
||||||
var albumid = page.album
|
const albumid = page.album
|
||||||
var previewsContainer = tabDiv.getElementsByClassName('uploads')[0]
|
const previewsContainer = tabDiv.getElementsByClassName('uploads')[0]
|
||||||
var urls = document.getElementById('urls').value
|
const urls = document.getElementById('urls').value
|
||||||
.split(/\r?\n/)
|
.split(/\r?\n/)
|
||||||
.filter(function (url) { return url.trim().length })
|
.filter(function (url) { return url.trim().length })
|
||||||
document.getElementById('urls').value = urls.join('\n')
|
document.getElementById('urls').value = urls.join('\n')
|
||||||
@ -321,22 +314,22 @@ page.uploadUrls = function (button) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tabDiv.getElementsByClassName('uploads')[0].style.display = 'block'
|
tabDiv.getElementsByClassName('uploads')[0].style.display = 'block'
|
||||||
var files = urls.map(function (url) {
|
const files = urls.map(function (url) {
|
||||||
var previewTemplate = document.createElement('template')
|
const previewTemplate = document.createElement('template')
|
||||||
previewTemplate.innerHTML = page.previewTemplate.trim()
|
previewTemplate.innerHTML = page.previewTemplate.trim()
|
||||||
var previewElement = previewTemplate.content.firstChild
|
const previewElement = previewTemplate.content.firstChild
|
||||||
previewElement.querySelector('.name').innerHTML = url
|
previewElement.querySelector('.name').innerHTML = url
|
||||||
previewsContainer.appendChild(previewElement)
|
previewsContainer.appendChild(previewElement)
|
||||||
return {
|
return {
|
||||||
url: url,
|
url,
|
||||||
previewElement: previewElement
|
previewElement
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function post (i) {
|
function post (i) {
|
||||||
if (i === files.length) { return done() }
|
if (i === files.length) { return done() }
|
||||||
|
|
||||||
var file = files[i]
|
const file = files[i]
|
||||||
|
|
||||||
function posted (result) {
|
function posted (result) {
|
||||||
file.previewElement.querySelector('.progress').style.display = 'none'
|
file.previewElement.querySelector('.progress').style.display = 'none'
|
||||||
@ -348,25 +341,21 @@ page.uploadUrls = function (button) {
|
|||||||
return post(i + 1)
|
return post(i + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
axios.post('api/upload',
|
axios.post('api/upload', {
|
||||||
{
|
urls: [file.url]
|
||||||
urls: [file.url]
|
}, {
|
||||||
},
|
headers: {
|
||||||
{
|
token: page.token,
|
||||||
headers: {
|
albumid
|
||||||
token: page.token,
|
}
|
||||||
albumid: albumid
|
}).then(function (response) {
|
||||||
}
|
return posted(response.data)
|
||||||
})
|
}).catch(function (error) {
|
||||||
.then(function (response) {
|
return posted({
|
||||||
return posted(response.data)
|
success: false,
|
||||||
})
|
description: error.toString()
|
||||||
.catch(function (error) {
|
|
||||||
return posted({
|
|
||||||
success: false,
|
|
||||||
description: error.toString()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return post(0)
|
return post(0)
|
||||||
}
|
}
|
||||||
@ -376,14 +365,14 @@ page.uploadUrls = function (button) {
|
|||||||
page.updateTemplate = function (file, response) {
|
page.updateTemplate = function (file, response) {
|
||||||
if (!response.url) { return }
|
if (!response.url) { return }
|
||||||
|
|
||||||
var a = file.previewElement.querySelector('.link > a')
|
const a = file.previewElement.querySelector('.link > a')
|
||||||
var clipboard = file.previewElement.querySelector('.clipboard-mobile > .clipboard-js')
|
const clipboard = file.previewElement.querySelector('.clipboard-mobile > .clipboard-js')
|
||||||
a.href = a.innerHTML = clipboard.dataset['clipboardText'] = response.url
|
a.href = a.innerHTML = clipboard.dataset['clipboardText'] = response.url
|
||||||
clipboard.parentElement.style.display = 'block'
|
clipboard.parentElement.style.display = 'block'
|
||||||
|
|
||||||
var exec = /.[\w]+(\?|$)/.exec(response.url)
|
const exec = /.[\w]+(\?|$)/.exec(response.url)
|
||||||
if (exec && exec[0] && imageExtensions.includes(exec[0].toLowerCase())) {
|
if (exec && exec[0] && page.imageExtensions.includes(exec[0].toLowerCase())) {
|
||||||
var img = file.previewElement.querySelector('img')
|
const img = file.previewElement.querySelector('img')
|
||||||
img.setAttribute('alt', response.name || '')
|
img.setAttribute('alt', response.name || '')
|
||||||
img.dataset['src'] = response.url
|
img.dataset['src'] = response.url
|
||||||
img.onerror = function () { this.style.display = 'none' } // hide webp in firefox and ie
|
img.onerror = function () { this.style.display = 'none' } // hide webp in firefox and ie
|
||||||
@ -392,30 +381,31 @@ page.updateTemplate = function (file, response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
page.createAlbum = function () {
|
page.createAlbum = function () {
|
||||||
var div = document.createElement('div')
|
const div = document.createElement('div')
|
||||||
div.innerHTML =
|
div.innerHTML = `
|
||||||
'<div class="field">\n' +
|
<div class="field">
|
||||||
' <label class="label">Album name</label>\n' +
|
<label class="label">Album name</label>
|
||||||
' <div class="controls">\n' +
|
<div class="controls">
|
||||||
' <input id="_name" class="input" type="text" placeholder="My super album">\n' +
|
<input id="swalName" class="input" type="text" placeholder="My super album">
|
||||||
' </div>\n' +
|
</div>
|
||||||
'</div>\n' +
|
</div>
|
||||||
'<div class="field">\n' +
|
<div class="field">
|
||||||
' <div class="control">\n' +
|
<div class="control">
|
||||||
' <label class="checkbox">\n' +
|
<label class="checkbox">
|
||||||
' <input id="_download" type="checkbox" checked>\n' +
|
<input id="swalDownload" type="checkbox" checked>
|
||||||
' Enable download\n' +
|
Enable download
|
||||||
' </label>\n' +
|
</label>
|
||||||
' </div>\n' +
|
</div>
|
||||||
'</div>\n' +
|
</div>
|
||||||
'<div class="field">\n' +
|
<div class="field">
|
||||||
' <div class="control">\n' +
|
<div class="control">
|
||||||
' <label class="checkbox">\n' +
|
<label class="checkbox">
|
||||||
' <input id="_public" type="checkbox" checked>\n' +
|
<input id="swalPublic" type="checkbox" checked>
|
||||||
' Enable public link\n' +
|
Enable public link
|
||||||
' </label>\n' +
|
</label>
|
||||||
' </div>\n' +
|
</div>
|
||||||
'</div>'
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
swal({
|
swal({
|
||||||
title: 'Create new album',
|
title: 'Create new album',
|
||||||
@ -427,43 +417,44 @@ page.createAlbum = function () {
|
|||||||
closeModal: false
|
closeModal: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).then(function (value) {
|
||||||
.then(function (value) {
|
if (!value) { return }
|
||||||
if (!value) { return }
|
|
||||||
|
|
||||||
var name = document.getElementById('_name').value
|
const name = document.getElementById('swalName').value
|
||||||
axios.post('api/albums', {
|
axios.post('api/albums', {
|
||||||
name: name,
|
name,
|
||||||
download: document.getElementById('_download').checked,
|
download: document.getElementById('swalDownload').checked,
|
||||||
public: document.getElementById('_public').checked
|
public: document.getElementById('swalPublic').checked
|
||||||
}, { headers: { token: page.token } })
|
}, {
|
||||||
.then(function (response) {
|
headers: {
|
||||||
if (response.data.success === false) {
|
token: page.token
|
||||||
return swal('An error occurred!', response.data.description, 'error')
|
}
|
||||||
}
|
}).then(function (response) {
|
||||||
|
if (response.data.success === false) {
|
||||||
|
return swal('An error occurred!', response.data.description, 'error')
|
||||||
|
}
|
||||||
|
|
||||||
var option = document.createElement('option')
|
const option = document.createElement('option')
|
||||||
option.value = response.data.id
|
option.value = response.data.id
|
||||||
option.innerHTML = name
|
option.innerHTML = name
|
||||||
page.albumSelect.appendChild(option)
|
page.albumSelect.appendChild(option)
|
||||||
|
|
||||||
swal('Woohoo!', 'Album was created successfully', 'success')
|
swal('Woohoo!', 'Album was created successfully', 'success')
|
||||||
})
|
}).catch(function (error) {
|
||||||
.catch(function (error) {
|
console.log(error)
|
||||||
console.log(error)
|
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
||||||
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle image paste event
|
// Handle image paste event
|
||||||
window.addEventListener('paste', function (event) {
|
window.addEventListener('paste', function (event) {
|
||||||
var items = (event.clipboardData || event.originalEvent.clipboardData).items
|
const items = (event.clipboardData || event.originalEvent.clipboardData).items
|
||||||
for (var index in items) {
|
for (const index in items) {
|
||||||
var item = items[index]
|
const item = items[index]
|
||||||
if (item.kind === 'file') {
|
if (item.kind === 'file') {
|
||||||
var blob = item.getAsFile()
|
const blob = item.getAsFile()
|
||||||
var file = new File([blob], 'pasted-image.' + blob.type.match(/(?:[^/]*\/)([^;]*)/)[1])
|
const file = new File([blob], `pasted-image.${blob.type.match(/(?:[^/]*\/)([^;]*)/)[1]}`)
|
||||||
file.type = blob.type
|
file.type = blob.type
|
||||||
page.dropzone.addFile(file)
|
page.dropzone.addFile(file)
|
||||||
}
|
}
|
||||||
@ -484,7 +475,9 @@ window.onload = function () {
|
|||||||
return swal('An error occurred!', 'There was an error when trying to copy the link to clipboard, please check the console for more information.', 'error')
|
return swal('An error occurred!', 'There was an error when trying to copy the link to clipboard, please check the console for more information.', 'error')
|
||||||
})
|
})
|
||||||
|
|
||||||
page.lazyLoad = new LazyLoad()
|
page.lazyLoad = new LazyLoad({
|
||||||
|
elements_selector: '.field.uploads img'
|
||||||
|
})
|
||||||
|
|
||||||
document.getElementById('createAlbum').addEventListener('click', function () {
|
document.getElementById('createAlbum').addEventListener('click', function () {
|
||||||
page.createAlbum()
|
page.createAlbum()
|
||||||
|
92
public/js/render.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/* global page, swal */
|
||||||
|
|
||||||
|
page.renderRoot = 'render/al/'
|
||||||
|
page.renderArray = [
|
||||||
|
'atago_1.png',
|
||||||
|
'atago_2.png',
|
||||||
|
'belfast_1.png',
|
||||||
|
'belfast_2.png',
|
||||||
|
'belfast_3.png',
|
||||||
|
'eldridge_1.png',
|
||||||
|
'hammann_1.png',
|
||||||
|
'hammann_2.png',
|
||||||
|
'javelin_1.png',
|
||||||
|
'kaga_1.png',
|
||||||
|
'laffey_1.png',
|
||||||
|
'prinz_eugen_1.png',
|
||||||
|
'prinz_eugen_2.png',
|
||||||
|
'takao_1.png',
|
||||||
|
'takao_2.png',
|
||||||
|
'unicorn_1.png',
|
||||||
|
'unicorn_2.png',
|
||||||
|
'unicorn_3.png',
|
||||||
|
'unicorn_4.png',
|
||||||
|
'unicorn_5.png',
|
||||||
|
'yamashiro_1.png'
|
||||||
|
]
|
||||||
|
page.render = null
|
||||||
|
|
||||||
|
page.doRenderSwal = function () {
|
||||||
|
const div = document.createElement('div')
|
||||||
|
div.innerHTML = `
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<label class="checkbox">
|
||||||
|
<input id="swalRender" type="checkbox" ${localStorage.render === '0' ? '' : 'checked'}>
|
||||||
|
Enable random render of ship waifu~
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p class="help">If disabled, you will still be able to see a small button on the bottom right corner of the screen to re-enable it.</p>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
swal({
|
||||||
|
content: div,
|
||||||
|
buttons: {
|
||||||
|
confirm: true
|
||||||
|
}
|
||||||
|
}).then(function (value) {
|
||||||
|
if (!value) { return }
|
||||||
|
const newValue = div.querySelector('#swalRender').checked ? undefined : '0'
|
||||||
|
if (newValue !== localStorage.render) {
|
||||||
|
newValue ? localStorage.render = newValue : localStorage.removeItem('render')
|
||||||
|
swal('Success!', `Render is now ${newValue ? 'disabled' : 'enabled'}.`, 'success')
|
||||||
|
const element = document.querySelector('body > .render')
|
||||||
|
element.remove()
|
||||||
|
page.doRender()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
page.getRenderVersion = function () {
|
||||||
|
const renderScript = document.getElementById('renderScript')
|
||||||
|
if (!renderScript) { return '' }
|
||||||
|
const match = renderScript.src.match(/\?v=\w*$/)
|
||||||
|
if (!match) { return '' }
|
||||||
|
return match[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
page.doRender = function () {
|
||||||
|
if (!page.renderRoot || !page.renderArray || !page.renderArray.length) { return }
|
||||||
|
|
||||||
|
let element
|
||||||
|
if (localStorage.render === '0') {
|
||||||
|
element = document.createElement('a')
|
||||||
|
element.className = 'button is-breeze is-hidden-mobile'
|
||||||
|
element.title = 'ship waifu~'
|
||||||
|
element.innerHTML = '<i class="icon-picture-1"></i>'
|
||||||
|
} else {
|
||||||
|
// Let us just allow people to get new render when toggling the option
|
||||||
|
page.render = page.renderArray[Math.floor(Math.random() * page.renderArray.length)]
|
||||||
|
element = document.createElement('img')
|
||||||
|
element.alt = element.title = 'ship waifu~'
|
||||||
|
element.className = 'is-hidden-mobile'
|
||||||
|
element.src = `${page.renderRoot}${page.render}${page.getRenderVersion()}`
|
||||||
|
}
|
||||||
|
|
||||||
|
element.classList.add('render')
|
||||||
|
element.addEventListener('click', page.doRenderSwal)
|
||||||
|
document.body.appendChild(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
page.doRender()
|
@ -2,24 +2,23 @@
|
|||||||
|
|
||||||
page.prepareShareX = function () {
|
page.prepareShareX = function () {
|
||||||
if (!page.token) { return }
|
if (!page.token) { return }
|
||||||
var origin = (location.hostname + location.pathname).replace(/\/(dashboard)?$/, '')
|
const origin = (location.hostname + location.pathname).replace(/\/(dashboard)?$/, '')
|
||||||
var originClean = origin.replace(/\//g, '_')
|
const originClean = origin.replace(/\//g, '_')
|
||||||
var sharexElement = document.getElementById('ShareX')
|
const sharexElement = document.getElementById('ShareX')
|
||||||
var sharexFile =
|
const sharexFile = `{
|
||||||
'{\r\n' +
|
"Name": "${originClean}",
|
||||||
' "Name": "' + originClean + '",\r\n' +
|
"DestinationType": "ImageUploader, FileUploader",
|
||||||
' "DestinationType": "ImageUploader, FileUploader",\r\n' +
|
"RequestType": "POST",
|
||||||
' "RequestType": "POST",\r\n' +
|
"RequestURL": "${location.protocol}//${origin}/api/upload",
|
||||||
' "RequestURL": "' + location.protocol + '//' + origin + '/api/upload",\r\n' +
|
"FileFormName": "files[]",
|
||||||
' "FileFormName": "files[]",\r\n' +
|
"Headers": {
|
||||||
' "Headers": {\r\n' +
|
"token": "${page.token}"
|
||||||
' "token": "' + page.token + '"\r\n' +
|
},
|
||||||
' },\r\n' +
|
"ResponseType": "Text",
|
||||||
' "ResponseType": "Text",\r\n' +
|
"URL": "$json:files[0].url$",
|
||||||
' "URL": "$json:files[0].url$",\r\n' +
|
"ThumbnailURL": "$json:files[0].url$"
|
||||||
' "ThumbnailURL": "$json:files[0].url$"\r\n' +
|
}\n`
|
||||||
'}'
|
const sharexBlob = new Blob([sharexFile], { type: 'application/octet-binary' })
|
||||||
var sharexBlob = new Blob([sharexFile], { type: 'application/octet-binary' })
|
|
||||||
sharexElement.setAttribute('href', URL.createObjectURL(sharexBlob))
|
sharexElement.setAttribute('href', URL.createObjectURL(sharexBlob))
|
||||||
sharexElement.setAttribute('download', originClean + '.sxcu')
|
sharexElement.setAttribute('download', `${originClean}.sxcu`)
|
||||||
}
|
}
|
||||||
|
29
public/libs/fontello/fontello.css
vendored
@ -1,11 +1,11 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'fontello';
|
font-family: 'fontello';
|
||||||
src: url('fontello.eot?61363773');
|
src: url('fontello.eot?54767678');
|
||||||
src: url('fontello.eot?61363773#iefix') format('embedded-opentype'),
|
src: url('fontello.eot?54767678#iefix') format('embedded-opentype'),
|
||||||
url('fontello.woff2?61363773') format('woff2'),
|
url('fontello.woff2?54767678') format('woff2'),
|
||||||
url('fontello.woff?61363773') format('woff'),
|
url('fontello.woff?54767678') format('woff'),
|
||||||
url('fontello.ttf?61363773') format('truetype'),
|
url('fontello.ttf?54767678') format('truetype'),
|
||||||
url('fontello.svg?61363773#fontello') format('svg');
|
url('fontello.svg?54767678#fontello') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
@ -33,6 +33,10 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
/* opacity: .8; */
|
/* opacity: .8; */
|
||||||
|
|
||||||
|
/* For safety - reset parent styles, that can break glyph codes*/
|
||||||
|
font-variant: normal;
|
||||||
|
text-transform: none;
|
||||||
|
|
||||||
/* fix buttons height, for twitter bootstrap */
|
/* fix buttons height, for twitter bootstrap */
|
||||||
/* line-height: 1em; */
|
/* line-height: 1em; */
|
||||||
|
|
||||||
@ -55,12 +59,12 @@
|
|||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-sharex:before { content: '\e800'; } /* '' */
|
.icon-pencil-1:before { content: '\e800'; } /* '' */
|
||||||
.icon-upload-cloud:before { content: '\e801'; } /* '' */
|
.icon-sharex:before { content: '\e801'; } /* '' */
|
||||||
.icon-picture-1:before { content: '\e802'; } /* '' */
|
.icon-upload-cloud:before { content: '\e802'; } /* '' */
|
||||||
.icon-th-list:before { content: '\e803'; } /* '' */
|
.icon-picture-1:before { content: '\e803'; } /* '' */
|
||||||
.icon-trash:before { content: '\e804'; } /* '' */
|
.icon-th-list:before { content: '\e804'; } /* '' */
|
||||||
.icon-pencil-1:before { content: '\e805'; } /* '' */
|
.icon-trash:before { content: '\e805'; } /* '' */
|
||||||
.icon-th-large:before { content: '\e806'; } /* '' */
|
.icon-th-large:before { content: '\e806'; } /* '' */
|
||||||
.icon-arrows-cw:before { content: '\e807'; } /* '' */
|
.icon-arrows-cw:before { content: '\e807'; } /* '' */
|
||||||
.icon-plus:before { content: '\e808'; } /* '' */
|
.icon-plus:before { content: '\e808'; } /* '' */
|
||||||
@ -72,6 +76,7 @@
|
|||||||
.icon-download:before { content: '\e80e'; } /* '' */
|
.icon-download:before { content: '\e80e'; } /* '' */
|
||||||
.icon-help-circled:before { content: '\e80f'; } /* '' */
|
.icon-help-circled:before { content: '\e80f'; } /* '' */
|
||||||
.icon-terminal:before { content: '\e810'; } /* '' */
|
.icon-terminal:before { content: '\e810'; } /* '' */
|
||||||
|
.icon-hammer:before { content: '\e811'; } /* '' */
|
||||||
.icon-github-circled:before { content: '\f09b'; } /* '' */
|
.icon-github-circled:before { content: '\f09b'; } /* '' */
|
||||||
.icon-gauge:before { content: '\f0e4'; } /* '' */
|
.icon-gauge:before { content: '\f0e4'; } /* '' */
|
||||||
.icon-paper-plane-empty:before { content: '\f1d9'; } /* '' */
|
.icon-paper-plane-empty:before { content: '\f1d9'; } /* '' */
|
||||||
|
@ -6,17 +6,17 @@
|
|||||||
<font id="fontello" horiz-adv-x="1000" >
|
<font id="fontello" horiz-adv-x="1000" >
|
||||||
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
||||||
<missing-glyph horiz-adv-x="1000" />
|
<missing-glyph horiz-adv-x="1000" />
|
||||||
<glyph glyph-name="sharex" unicode="" d="M328-73c-98 10-183 74-229 171-52 110-43 246 24 346 44 66 107 110 181 126 21 4 70 4 91 0 45-10 86-30 120-59 7-5 12-10 12-10-1 0-10-2-20-4-122-17-223-98-257-205-10-29-12-45-12-79 0-34 2-50 12-80 14-41 35-75 70-109 32-33 64-55 107-72l16-7-7-3c-12-5-45-13-65-15-20-2-25-2-43 0z m248-11c-64 5-121 24-170 56-66 44-110 108-126 182-4 21-4 70 1 91 9 45 29 86 58 120 5 7 10 12 10 12 1-1 2-10 4-20 17-122 98-223 205-257 29-10 45-12 79-12 46 0 74 7 117 28 62 31 115 90 144 161l7 16 3-7c10-23 18-74 16-99-8-103-72-190-172-238-53-25-120-38-176-33z m42 212c-45 7-90 27-127 55-20 16-20 17-9 18 129 16 233 97 268 207 10 29 12 45 12 79 0 46-7 74-28 117-30 61-88 114-157 142-13 6-19 9-17 10 4 3 35 12 50 14 24 5 42 5 62 3 65-7 122-35 170-85 24-25 39-47 55-78 22-43 33-84 37-134 6-77-15-157-56-220-44-65-107-109-180-125-15-4-64-5-80-3z m31 204c-16 129-97 233-207 268-29 10-45 12-79 12-44 0-72-7-112-25-30-15-51-30-77-56-33-33-55-65-72-108l-7-16-3 7c-10 23-18 74-16 99 9 103 72 190 172 238 81 39 178 44 264 16 38-12 67-27 98-50 55-42 95-103 109-169 4-18 6-57 3-76-6-47-25-92-55-131-16-20-16-20-18-9z" horiz-adv-x="1000" />
|
<glyph glyph-name="pencil-1" unicode="" d="M0-143l68 343 274-273z m137 392l422 422 259-260-421-422z m531 494q2 39 31 69t69 31 66-25l131-131q25-26 24-66t-30-69-69-30-66 24l-131 131q-27 27-25 66z" horiz-adv-x="989" />
|
||||||
|
|
||||||
<glyph glyph-name="upload-cloud" unicode="" d="M781 506q108 0 184-76t76-184-76-184-184-77l-208 0 0 239 67-66q16-17 38-17 20 0 36 17 15 15 15 36t-15 36l-156 156q-14 14-37 15t-37-15l-156-156q-15-15-15-36t15-36q16-17 37-17 20 0 36 17l68 66 0-239-260 0q-86 0-148 61t-61 148q0 72 44 128t112 73l0 8q0 130 92 221t221 91q100 0 180-58t114-152q2 0 8 1t10 0z" horiz-adv-x="1041" />
|
<glyph glyph-name="sharex" unicode="" d="M328-73c-98 10-183 74-229 171-52 110-43 246 24 346 44 66 107 110 181 126 21 4 70 4 91 0 45-10 86-30 120-59 7-5 12-10 12-10-1 0-10-2-20-4-122-17-223-98-257-205-10-29-12-45-12-79 0-34 2-50 12-80 14-41 35-75 70-109 32-33 64-55 107-72l16-7-7-3c-12-5-45-13-65-15-20-2-25-2-43 0z m248-11c-64 5-121 24-170 56-66 44-110 108-126 182-4 21-4 70 1 91 9 45 29 86 58 120 5 7 10 12 10 12 1-1 2-10 4-20 17-122 98-223 205-257 29-10 45-12 79-12 46 0 74 7 117 28 62 31 115 90 144 161l7 16 3-7c10-23 18-74 16-99-8-103-72-190-172-238-53-25-120-38-176-33z m42 212c-45 7-90 27-127 55-20 16-20 17-9 18 129 16 233 97 268 207 10 29 12 45 12 79 0 46-7 74-28 117-30 61-88 114-157 142-13 6-19 9-17 10 4 3 35 12 50 14 24 5 42 5 62 3 65-7 122-35 170-85 24-25 39-47 55-78 22-43 33-84 37-134 6-77-15-157-56-220-44-65-107-109-180-125-15-4-64-5-80-3z m31 204c-16 129-97 233-207 268-29 10-45 12-79 12-44 0-72-7-112-25-30-15-51-30-77-56-33-33-55-65-72-108l-7-16-3 7c-10 23-18 74-16 99 9 103 72 190 172 238 81 39 178 44 264 16 38-12 67-27 98-50 55-42 95-103 109-169 4-18 6-57 3-76-6-47-25-92-55-131-16-20-16-20-18-9z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="picture-1" unicode="" d="M0-68l0 836 1000 0 0-836-1000 0z m76 78l848 0 0 680-848 0 0-680z m90 80l0 59 150 195 102-86 193 291 223-228 0-231-668 0z m0 416q0 37 24 62t62 24q33 0 58-24t24-62q0-33-24-57t-58-25q-37 0-62 25t-24 57z" horiz-adv-x="1000" />
|
<glyph glyph-name="upload-cloud" unicode="" d="M781 506q108 0 184-76t76-184-76-184-184-77l-208 0 0 239 67-66q16-17 38-17 20 0 36 17 15 15 15 36t-15 36l-156 156q-14 14-37 15t-37-15l-156-156q-15-15-15-36t15-36q16-17 37-17 20 0 36 17l68 66 0-239-260 0q-86 0-148 61t-61 148q0 72 44 128t112 73l0 8q0 130 92 221t221 91q100 0 180-58t114-152q2 0 8 1t10 0z" horiz-adv-x="1041" />
|
||||||
|
|
||||||
<glyph glyph-name="th-list" unicode="" d="M860 90q43 0 73-31t31-74q0-43-31-73t-73-31l-365 0q-44 0-74 31t-31 73 31 74 74 31l365 0z m0 364q43 0 73-31t31-73-31-73-73-31l-365 0q-44 0-74 31t-31 73 31 73 74 31l365 0z m0 365q43 0 73-31t31-73q0-44-31-74t-73-31l-365 0q-42 0-74 31t-31 74 31 73 74 31l365 0z m-860-834q0 130 130 130t130-130-130-130-130 130z m0 365q0 130 130 130t130-130-130-130-130 130z m0 365q0 130 130 130t130-130-130-130-130 130z" horiz-adv-x="964" />
|
<glyph glyph-name="picture-1" unicode="" d="M0-68l0 836 1000 0 0-836-1000 0z m76 78l848 0 0 680-848 0 0-680z m90 80l0 59 150 195 102-86 193 291 223-228 0-231-668 0z m0 416q0 37 24 62t62 24q33 0 58-24t24-62q0-33-24-57t-58-25q-37 0-62 25t-24 57z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="trash" unicode="" d="M0 633l0 141 289 0 0 76 246 0 0-76 289 0 0-141-824 0z m43-783l0 676 738 0 0-676-738 0z" horiz-adv-x="824" />
|
<glyph glyph-name="th-list" unicode="" d="M860 90q43 0 73-31t31-74q0-43-31-73t-73-31l-365 0q-44 0-74 31t-31 73 31 74 74 31l365 0z m0 364q43 0 73-31t31-73-31-73-73-31l-365 0q-44 0-74 31t-31 73 31 73 74 31l365 0z m0 365q43 0 73-31t31-73q0-44-31-74t-73-31l-365 0q-42 0-74 31t-31 74 31 73 74 31l365 0z m-860-834q0 130 130 130t130-130-130-130-130 130z m0 365q0 130 130 130t130-130-130-130-130 130z m0 365q0 130 130 130t130-130-130-130-130 130z" horiz-adv-x="964" />
|
||||||
|
|
||||||
<glyph glyph-name="pencil-1" unicode="" d="M0-143l68 343 274-273z m137 392l422 422 259-260-421-422z m531 494q2 39 31 69t69 31 66-25l131-131q25-26 24-66t-30-69-69-30-66 24l-131 131q-27 27-25 66z" horiz-adv-x="989" />
|
<glyph glyph-name="trash" unicode="" d="M0 633l0 141 289 0 0 76 246 0 0-76 289 0 0-141-824 0z m43-783l0 676 738 0 0-676-738 0z" horiz-adv-x="824" />
|
||||||
|
|
||||||
<glyph glyph-name="th-large" unicode="" d="M0 663q0 65 46 110t110 46l104 0q65 0 111-46t45-110l0-104q0-65-45-111t-111-45l-104 0q-65 0-110 45t-46 111l0 104z m521 0q0 65 46 110t111 46l103 0q65 0 111-46t46-110l0-104q0-65-46-111t-111-45l-103 0q-65 0-111 45t-46 111l0 104z m-521-521q0 65 46 110t110 46l104 0q65 0 111-46t45-110l0-104q0-65-45-111t-111-46l-104 0q-65 0-110 46t-46 111l0 104z m521 0q0 65 46 110t111 46l103 0q65 0 111-46t46-110l0-104q0-65-46-111t-111-46l-103 0q-65 0-111 46t-46 111l0 104z" horiz-adv-x="938" />
|
<glyph glyph-name="th-large" unicode="" d="M0 663q0 65 46 110t110 46l104 0q65 0 111-46t45-110l0-104q0-65-45-111t-111-45l-104 0q-65 0-110 45t-46 111l0 104z m521 0q0 65 46 110t111 46l103 0q65 0 111-46t46-110l0-104q0-65-46-111t-111-45l-103 0q-65 0-111 45t-46 111l0 104z m-521-521q0 65 46 110t110 46l104 0q65 0 111-46t45-110l0-104q0-65-45-111t-111-46l-104 0q-65 0-110 46t-46 111l0 104z m521 0q0 65 46 110t111 46l103 0q65 0 111-46t46-110l0-104q0-65-46-111t-111-46l-103 0q-65 0-111 46t-46 111l0 104z" horiz-adv-x="938" />
|
||||||
|
|
||||||
@ -40,6 +40,8 @@
|
|||||||
|
|
||||||
<glyph glyph-name="terminal" unicode="" d="M929 779h-858c-39 0-71-32-71-72v-714c0-40 32-72 71-72h858c39 0 71 32 71 72v714c0 40-32 72-71 72z m-786-500l143 142-143 143 71 72 215-215-215-214-71 72z m571-72h-285v72h285v-72z" horiz-adv-x="1000" />
|
<glyph glyph-name="terminal" unicode="" d="M929 779h-858c-39 0-71-32-71-72v-714c0-40 32-72 71-72h858c39 0 71 32 71 72v714c0 40-32 72-71 72z m-786-500l143 142-143 143 71 72 215-215-215-214-71 72z m571-72h-285v72h285v-72z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
|
<glyph glyph-name="hammer" unicode="" d="M988-7q0-30-20-50l-60-61q-22-20-51-20-29 0-50 20l-203 204q-21 20-21 50 0 29 24 53l-143 143-70-70q-8-8-19-8t-19 8q1-1 7-7t7-7 6-6 5-8 4-8 3-9 0-10q0-21-15-38-2-1-9-10t-11-11-10-9-13-9-12-5-14-3q-23 0-38 16l-228 228q-16 15-16 38 0 7 3 14t5 12 9 13 9 10 11 11 10 9q17 15 38 15 6 0 10 0t9-3 8-4 8-5 6-6 7-7 7-7q-8 8-8 19t8 19l194 194q8 8 19 8t19-8q-1 1-7 7t-7 7-6 7-5 7-3 8-4 9 0 10q0 21 15 38 2 2 9 10t11 11 10 10 13 8 12 5 14 3q23 0 38-16l228-228q16-15 16-38 0-7-3-14t-5-12-8-13-10-10-11-11-10-9q-17-15-38-15-6 0-10 0t-9 4-8 3-7 5-7 6-7 7-7 7q8-8 8-19t-8-19l-70-70 143-143q24 24 53 24 29 0 51-21l203-202q20-22 20-51z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="github-circled" unicode="" d="M429 779q116 0 215-58t156-156 57-215q0-140-82-252t-211-155q-15-3-22 4t-7 17q0 1 0 43t0 75q0 54-29 79 32 3 57 10t53 22 45 37 30 58 11 84q0 67-44 115 21 51-4 114-16 5-46-6t-51-25l-21-13q-52 15-107 15t-108-15q-8 6-23 15t-47 22-47 7q-25-63-5-114-44-48-44-115 0-47 12-83t29-59 45-37 52-22 57-10q-21-20-27-58-12-5-25-8t-32-3-36 12-31 35q-11 18-27 29t-28 14l-11 1q-12 0-16-2t-3-7 5-8 7-6l4-3q12-6 24-21t18-29l6-13q7-21 24-34t37-17 39-3 31 1l13 3q0-22 0-50t1-30q0-10-8-17t-22-4q-129 43-211 155t-82 252q0 117 58 215t155 156 216 58z m-267-616q2 4-3 7-6 1-8-1-1-4 4-7 5-3 7 1z m18-19q4 3-1 9-6 5-9 2-4-3 1-9 5-6 9-2z m16-25q6 4 0 11-4 7-9 3-5-3 0-10t9-4z m24-23q4 4-2 10-7 7-11 2-5-5 2-11 6-6 11-1z m32-14q1 6-8 9-8 2-10-4t7-9q8-3 11 4z m35-3q0 7-10 6-9 0-9-6 0-7 10-6 9 0 9 6z m32 5q-1 7-10 5-9-1-8-8t10-4 8 7z" horiz-adv-x="857.1" />
|
<glyph glyph-name="github-circled" unicode="" d="M429 779q116 0 215-58t156-156 57-215q0-140-82-252t-211-155q-15-3-22 4t-7 17q0 1 0 43t0 75q0 54-29 79 32 3 57 10t53 22 45 37 30 58 11 84q0 67-44 115 21 51-4 114-16 5-46-6t-51-25l-21-13q-52 15-107 15t-108-15q-8 6-23 15t-47 22-47 7q-25-63-5-114-44-48-44-115 0-47 12-83t29-59 45-37 52-22 57-10q-21-20-27-58-12-5-25-8t-32-3-36 12-31 35q-11 18-27 29t-28 14l-11 1q-12 0-16-2t-3-7 5-8 7-6l4-3q12-6 24-21t18-29l6-13q7-21 24-34t37-17 39-3 31 1l13 3q0-22 0-50t1-30q0-10-8-17t-22-4q-129 43-211 155t-82 252q0 117 58 215t155 156 216 58z m-267-616q2 4-3 7-6 1-8-1-1-4 4-7 5-3 7 1z m18-19q4 3-1 9-6 5-9 2-4-3 1-9 5-6 9-2z m16-25q6 4 0 11-4 7-9 3-5-3 0-10t9-4z m24-23q4 4-2 10-7 7-11 2-5-5 2-11 6-6 11-1z m32-14q1 6-8 9-8 2-10-4t7-9q8-3 11 4z m35-3q0 7-10 6-9 0-9-6 0-7 10-6 9 0 9 6z m32 5q-1 7-10 5-9-1-8-8t10-4 8 7z" horiz-adv-x="857.1" />
|
||||||
|
|
||||||
<glyph glyph-name="gauge" unicode="" d="M214 207q0 30-21 51t-50 21-51-21-21-51 21-50 51-21 50 21 21 50z m107 250q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m239-268l57 213q3 14-5 27t-21 16-27-3-17-22l-56-213q-33-3-60-25t-35-55q-11-43 11-81t66-50 81 11 50 66q9 33-4 65t-40 51z m369 18q0 30-21 51t-51 21-50-21-21-51 21-50 50-21 51 21 21 50z m-358 357q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m250-107q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m179-250q0-145-79-269-10-17-30-17h-782q-20 0-30 17-79 123-79 269 0 102 40 194t106 160 160 107 194 39 194-39 160-107 106-160 40-194z" horiz-adv-x="1000" />
|
<glyph glyph-name="gauge" unicode="" d="M214 207q0 30-21 51t-50 21-51-21-21-51 21-50 51-21 50 21 21 50z m107 250q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m239-268l57 213q3 14-5 27t-21 16-27-3-17-22l-56-213q-33-3-60-25t-35-55q-11-43 11-81t66-50 81 11 50 66q9 33-4 65t-40 51z m369 18q0 30-21 51t-51 21-50-21-21-51 21-50 50-21 51 21 21 50z m-358 357q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m250-107q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m179-250q0-145-79-269-10-17-30-17h-782q-20 0-30 17-79 123-79 269 0 102 40 194t106 160 160 107 194 39 194-39 160-107 106-160 40-194z" horiz-adv-x="1000" />
|
||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
2
public/libs/lazyload/lazyload.min.js
vendored
BIN
public/render/al/atago_1.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
public/render/al/atago_2.png
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
public/render/al/belfast_1.png
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
public/render/al/belfast_2.png
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
public/render/al/belfast_3.png
Normal file
After Width: | Height: | Size: 96 KiB |
BIN
public/render/al/eldridge_1.png
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
public/render/al/hammann_1.png
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
public/render/al/hammann_2.png
Normal file
After Width: | Height: | Size: 91 KiB |
BIN
public/render/al/javelin_1.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
public/render/al/kaga_1.png
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
public/render/al/laffey_1.png
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
public/render/al/prinz_eugen_1.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
public/render/al/prinz_eugen_2.png
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
public/render/al/takao_1.png
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
public/render/al/takao_2.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
public/render/al/unicorn_1.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
public/render/al/unicorn_2.png
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
public/render/al/unicorn_3.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
public/render/al/unicorn_4.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
public/render/al/unicorn_5.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
public/render/al/yamashiro_1.png
Normal file
After Width: | Height: | Size: 87 KiB |
@ -41,5 +41,8 @@ routes.post('/tokens/verify', (req, res, next) => tokenController.verify(req, re
|
|||||||
routes.post('/tokens/change', (req, res, next) => tokenController.change(req, res, next))
|
routes.post('/tokens/change', (req, res, next) => tokenController.change(req, res, next))
|
||||||
routes.get('/filelength/config', (req, res, next) => authController.getFileLengthConfig(req, res, next))
|
routes.get('/filelength/config', (req, res, next) => authController.getFileLengthConfig(req, res, next))
|
||||||
routes.post('/filelength/change', (req, res, next) => authController.changeFileLength(req, res, next))
|
routes.post('/filelength/change', (req, res, next) => authController.changeFileLength(req, res, next))
|
||||||
|
routes.get('/users', (req, res, next) => authController.listUsers(req, res, next))
|
||||||
|
routes.get('/users/:page', (req, res, next) => authController.listUsers(req, res, next))
|
||||||
|
routes.post('/users/edit', (req, res, next) => authController.editUser(req, res, next))
|
||||||
|
|
||||||
module.exports = routes
|
module.exports = routes
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
v2: Images and config files (manifest.json, browserconfig.xml, etc).
|
v2: Images and config files (manifest.json, browserconfig.xml, etc).
|
||||||
v3: CSS and JS files (libs such as bulma, lazyload, etc).
|
v3: CSS and JS files (libs such as bulma, lazyload, etc).
|
||||||
#}
|
#}
|
||||||
{% set v1 = "UW9mVRyFee" %}
|
{% set v1 = "LZ9JN4pnIf" %}
|
||||||
{% set v2 = "Ii3JYKIhb0" %}
|
{% set v2 = "Ii3JYKIhb0" %}
|
||||||
{% set v3 = "HrvcYD3KTh" %}
|
{% set v3 = "6MfcbDZldp" %}
|
||||||
|
|
||||||
{#
|
{#
|
||||||
These will be the links in the homepage and the No-JS uploader.
|
These will be the links in the homepage and the No-JS uploader.
|
||||||
|
@ -70,6 +70,15 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class="menu-label">Administration</p>
|
<p class="menu-label">Administration</p>
|
||||||
|
<ul class="menu-list">
|
||||||
|
<li>
|
||||||
|
<a id="itemManageUploads" disabled>Manage uploads</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a id="itemManageUsers" disabled>Manage users</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p class="menu-label">Configuration</p>
|
||||||
<ul class="menu-list">
|
<ul class="menu-list">
|
||||||
<li>
|
<li>
|
||||||
<a id="ShareX">ShareX user profile</a>
|
<a id="ShareX">ShareX user profile</a>
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
<script type="text/javascript" src="libs/lazyload/lazyload.min.js?v={{ globals.v3 }}"></script>
|
<script type="text/javascript" src="libs/lazyload/lazyload.min.js?v={{ globals.v3 }}"></script>
|
||||||
<script type="text/javascript" src="js/home.js?v={{ globals.v1 }}"></script>
|
<script type="text/javascript" src="js/home.js?v={{ globals.v1 }}"></script>
|
||||||
<script type="text/javascript" src="js/sharex.js?v={{ globals.v1 }}"></script>
|
<script type="text/javascript" src="js/sharex.js?v={{ globals.v1 }}"></script>
|
||||||
|
<!-- We assign an ID for this so that the script can find out its own version string -->
|
||||||
|
<script id="renderScript" type="text/javascript" src="js/render.js?v={{ globals.v1 }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@ -126,7 +128,7 @@
|
|||||||
{% include "_partial/links.njk" %}
|
{% include "_partial/links.njk" %}
|
||||||
|
|
||||||
{% if gitHash -%}
|
{% if gitHash -%}
|
||||||
<p>Git commit: <a href="https://github.com/BobbyWibowo/lolisafe/commit/{{ gitHash }}" target="_blank" rel="noopener">{{ gitHash }}</a></p>
|
<p class="git-commit">Git commit: <a class="is-dotted" href="https://github.com/BobbyWibowo/lolisafe/commit/{{ gitHash }}" target="_blank" rel="noopener">{{ gitHash }}</a></p>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|