feat: code cleanup, new features and v2.0

We're merging this to continue https://github.com/filebrowser/filebrowser/pull/575 and setup translations auto-updating.
This commit is contained in:
Henrique Dias
2019-01-05 16:12:09 +00:00
committed by GitHub
parent 2642333928
commit 39be89780e
155 changed files with 16499 additions and 6583 deletions

View File

@@ -1,478 +0,0 @@
import store from '@/store'
const ssl = (window.location.protocol === 'https:')
export function removePrefix (url) {
if (url.startsWith('/files')) {
url = url.slice(6)
}
if (url === '') url = '/'
if (url[0] !== '/') url = '/' + url
return url
}
export function fetch (url) {
url = removePrefix(url)
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('GET', `${store.state.baseURL}/api/resource${url}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
switch (request.status) {
case 200:
resolve(JSON.parse(request.responseText))
break
default:
reject(new Error(request.status))
break
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
export function remove (url) {
url = removePrefix(url)
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('DELETE', `${store.state.baseURL}/api/resource${url}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
if (request.status === 200) {
resolve(request.responseText)
} else {
reject(request.responseText)
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
export function post (url, content = '', overwrite = false, onupload) {
url = removePrefix(url)
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('POST', `${store.state.baseURL}/api/resource${url}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
if (typeof onupload === 'function') {
request.upload.onprogress = onupload
}
if (overwrite) {
request.setRequestHeader('Action', `override`)
}
request.onload = () => {
if (request.status === 200) {
resolve(request.responseText)
} else if (request.status === 409) {
reject(request.status)
} else {
reject(request.responseText)
}
}
request.onerror = (error) => {
reject(error)
}
request.send(content)
})
}
export function put (url, content = '', publish = false, date = '') {
url = removePrefix(url)
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('PUT', `${store.state.baseURL}/api/resource${url}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.setRequestHeader('Publish', publish)
if (date !== '') {
request.setRequestHeader('Schedule', date)
}
request.onload = () => {
if (request.status === 200) {
resolve(request.responseText)
} else {
reject(request.responseText)
}
}
request.onerror = (error) => reject(error)
request.send(content)
})
}
function moveCopy (items, copy = false) {
let promises = []
for (let item of items) {
let from = removePrefix(item.from)
let to = removePrefix(item.to)
promises.push(new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('PATCH', `${store.state.baseURL}/api/resource${from}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.setRequestHeader('Destination', to)
if (copy) {
request.setRequestHeader('Action', 'copy')
}
request.onload = () => {
if (request.status === 200) {
resolve(request.responseText)
} else {
reject(request.responseText)
}
}
request.onerror = (error) => reject(error)
request.send()
}))
}
return Promise.all(promises)
}
export function move (items) {
return moveCopy(items)
}
export function copy (items) {
return moveCopy(items, true)
}
export function checksum (url, algo) {
url = removePrefix(url)
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('GET', `${store.state.baseURL}/api/checksum${url}?algo=${algo}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
if (request.status === 200) {
resolve(request.responseText)
} else {
reject(request.responseText)
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
export function command (url, command, onmessage, onclose) {
let protocol = (ssl ? 'wss:' : 'ws:')
url = removePrefix(url)
url = `${protocol}//${window.location.host}${store.state.baseURL}/api/command${url}`
let conn = new window.WebSocket(url)
conn.onopen = () => conn.send(command)
conn.onmessage = onmessage
conn.onclose = onclose
}
export function search (url, search, onmessage, onclose) {
let protocol = (ssl ? 'wss:' : 'ws:')
url = removePrefix(url)
url = `${protocol}//${window.location.host}${store.state.baseURL}/api/search${url}`
let conn = new window.WebSocket(url)
conn.onopen = () => conn.send(search)
conn.onmessage = onmessage
conn.onclose = onclose
}
export function download (format, ...files) {
let url = `${store.state.baseURL}/api/download`
if (files.length === 1) {
url += removePrefix(files[0]) + '?'
} else {
let arg = ''
for (let file of files) {
arg += removePrefix(file) + ','
}
arg = arg.substring(0, arg.length - 1)
arg = encodeURIComponent(arg)
url += `/?files=${arg}&`
}
if (format !== null) {
url += `&format=${format}`
}
window.open(url)
}
export function getSettings () {
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('GET', `${store.state.baseURL}/api/settings/`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
switch (request.status) {
case 200:
resolve(JSON.parse(request.responseText))
break
default:
reject(request.responseText)
break
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
export function updateSettings (param, which) {
return new Promise((resolve, reject) => {
let data = {
what: 'settings',
which: which,
data: {}
}
data.data[which] = param
let request = new window.XMLHttpRequest()
request.open('PUT', `${store.state.baseURL}/api/settings/`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
switch (request.status) {
case 200:
resolve()
break
default:
reject(request.responseText)
break
}
}
request.onerror = (error) => { reject(error) }
request.send(JSON.stringify(data))
})
}
// USERS
export function getUsers () {
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('GET', `${store.state.baseURL}/api/users/`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
switch (request.status) {
case 200:
resolve(JSON.parse(request.responseText))
break
default:
reject(request.responseText)
break
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
export function getUser (id) {
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('GET', `${store.state.baseURL}/api/users/${id}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
switch (request.status) {
case 200:
resolve(JSON.parse(request.responseText))
break
default:
reject(request.responseText)
break
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
export function newUser (user) {
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('POST', `${store.state.baseURL}/api/users/`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
switch (request.status) {
case 201:
resolve(request.getResponseHeader('Location'))
break
default:
reject(request.responseText)
break
}
}
request.onerror = (error) => reject(error)
request.send(JSON.stringify({
what: 'user',
which: 'new',
data: user
}))
})
}
export function updateUser (user, which) {
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('PUT', `${store.state.baseURL}/api/users/${user.ID}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
switch (request.status) {
case 200:
resolve(request.getResponseHeader('Location'))
break
default:
reject(request.responseText)
break
}
}
request.onerror = (error) => reject(error)
request.send(JSON.stringify({
what: 'user',
which: (typeof which === 'string') ? which : 'all',
data: user
}))
})
}
export function deleteUser (id) {
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('DELETE', `${store.state.baseURL}/api/users/${id}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
switch (request.status) {
case 200:
resolve()
break
default:
reject(request.responseText)
break
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
// SHARE
export function getShare (url) {
url = removePrefix(url)
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('GET', `${store.state.baseURL}/api/share${url}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
if (request.status === 200) {
resolve(JSON.parse(request.responseText))
} else {
reject(request.status)
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
export function deleteShare (hash) {
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('DELETE', `${store.state.baseURL}/api/share/${hash}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
if (request.status === 200) {
resolve()
} else {
reject(request.status)
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
export function share (url, expires = '', unit = 'hours') {
url = removePrefix(url)
url = `${store.state.baseURL}/api/share${url}`
if (expires !== '') {
url += `?expires=${expires}&unit=${unit}`
}
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('POST', url, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
if (request.status === 200) {
resolve(JSON.parse(request.responseText))
} else {
reject(request.responseStatus)
}
}
request.onerror = (error) => reject(error)
request.send()
})
}
export function subtitles (url) {
url = removePrefix(url)
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('GET', `${store.state.baseURL}/api/subtitles${url}`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
request.onload = () => {
switch (request.status) {
case 200:
resolve(JSON.parse(request.responseText))
break
default:
reject(new Error(request.status))
break
}
}
request.onerror = (error) => reject(error)
request.send()
})
}

View File

@@ -1,69 +1,92 @@
import cookie from './cookie'
import store from '@/store'
import router from '@/router'
import { Base64 } from 'js-base64'
import { baseURL } from '@/utils/constants'
function parseToken (token) {
let path = store.state.baseURL
if (path === '') path = '/'
document.cookie = `auth=${token}; max-age=86400; path=${path}`
let res = token.split('.')
let user = JSON.parse(Base64.decode(res[1]))
if (!user.commands) {
user.commands = []
export function parseToken (token) {
const parts = token.split('.')
if (parts.length !== 3) {
throw new Error('token malformed')
}
const data = JSON.parse(Base64.decode(parts[1]))
if (Math.round(new Date().getTime() / 1000) > data.exp) {
throw new Error('token expired')
}
localStorage.setItem('jwt', token)
store.commit('setJWT', token)
store.commit('setUser', user)
store.commit('setUser', data.user)
}
function loggedIn () {
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('GET', `${store.state.baseURL}/api/auth/renew`, true)
if (!store.state.noAuth) request.setRequestHeader('Authorization', `Bearer ${cookie('auth')}`)
request.onload = () => {
if (request.status === 200) {
parseToken(request.responseText)
resolve()
} else {
reject(new Error(request.responseText))
}
export async function validateLogin () {
try {
if (localStorage.getItem('jwt')) {
await renew(localStorage.getItem('jwt'))
}
request.onerror = () => reject(new Error('Could not finish the request'))
request.send()
})
} catch (_) {
console.warn('Invalid JWT token in storage') // eslint-disable-line
}
}
function login (user, password, captcha) {
let data = {username: user, password: password, recaptcha: captcha}
return new Promise((resolve, reject) => {
let request = new window.XMLHttpRequest()
request.open('POST', `${store.state.baseURL}/api/auth/get`, true)
export async function login (username, password, recaptcha) {
const data = { username, password, recaptcha }
request.onload = () => {
if (request.status === 200) {
parseToken(request.responseText)
resolve()
} else {
reject(request.responseText)
}
const res = await fetch(`${baseURL}/api/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
const body = await res.text()
if (res.status === 200) {
parseToken(body)
} else {
throw new Error(body)
}
}
export async function renew (jwt) {
const res = await fetch(`${baseURL}/api/renew`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwt}`,
}
request.onerror = () => reject(new Error('Could not finish the request'))
request.send(JSON.stringify(data))
})
const body = await res.text()
if (res.status === 200) {
parseToken(body)
} else {
throw new Error(body)
}
}
function logout () {
let path = store.state.baseURL
if (path === '') path = '/'
document.cookie = `auth='nothing'; max-age=0; path=${path}`
export async function signup (username, password) {
const data = { username, password }
const res = await fetch(`${baseURL}/api/signup`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
if (res.status !== 200) {
throw new Error(res.status)
}
}
export function logout () {
store.commit('setJWT', '')
store.commit('setUser', null)
localStorage.setItem('jwt', null)
router.push({path: '/login'})
}
export default {
loggedIn: loggedIn,
login: login,
logout: logout
}

View File

@@ -2,7 +2,7 @@ function loading (button) {
let el = document.querySelector(`#${button}-button > i`)
if (el === undefined || el === null) {
console.log('Error getting button ' + button)
console.log('Error getting button ' + button) // eslint-disable-line
return
}
@@ -20,7 +20,7 @@ function done (button) {
let el = document.querySelector(`#${button}-button > i`)
if (el === undefined || el === null) {
console.log('Error getting button ' + button)
console.log('Error getting button ' + button) // eslint-disable-line
return
}
@@ -37,7 +37,7 @@ function success (button) {
let el = document.querySelector(`#${button}-button > i`)
if (el === undefined || el === null) {
console.log('Error getting button ' + button)
console.log('Error getting button ' + button) // eslint-disable-line
return
}

View File

@@ -1,60 +0,0 @@
// Most of the code from this file comes from:
// https://github.com/codemirror/CodeMirror/blob/master/addon/mode/loadmode.js
import * as CodeMirror from 'codemirror'
import store from '@/store'
// Make CodeMirror available globally so the modes' can register themselves.
window.CodeMirror = CodeMirror
CodeMirror.modeURL = store.state.baseURL + '/static/js/codemirror/mode/%N/%N.js'
var loading = {}
function splitCallback (cont, n) {
var countDown = n
return function () {
if (--countDown === 0) cont()
}
}
function ensureDeps (mode, cont) {
var deps = CodeMirror.modes[mode].dependencies
if (!deps) return cont()
var missing = []
for (var i = 0; i < deps.length; ++i) {
if (!CodeMirror.modes.hasOwnProperty(deps[i])) missing.push(deps[i])
}
if (!missing.length) return cont()
var split = splitCallback(cont, missing.length)
for (i = 0; i < missing.length; ++i) CodeMirror.requireMode(missing[i], split)
}
CodeMirror.requireMode = function (mode, cont) {
if (typeof mode !== 'string') mode = mode.name
if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont)
if (loading.hasOwnProperty(mode)) return loading[mode].push(cont)
var file = CodeMirror.modeURL.replace(/%N/g, mode)
var script = document.createElement('script')
script.src = file
var others = document.getElementsByTagName('script')[0]
var list = loading[mode] = [cont]
CodeMirror.on(script, 'load', function () {
ensureDeps(mode, function () {
for (var i = 0; i < list.length; ++i) list[i]()
})
})
others.parentNode.insertBefore(script, others)
}
CodeMirror.autoLoadMode = function (instance, mode) {
if (CodeMirror.modes.hasOwnProperty(mode)) return
CodeMirror.requireMode(mode, function () {
instance.setOption('mode', mode)
})
}
export default CodeMirror

22
src/utils/constants.js Normal file
View File

@@ -0,0 +1,22 @@
const name = window.FileBrowser.Name || 'File Browser'
const disableExternal = window.FileBrowser.DisableExternal
const baseURL = window.FileBrowser.BaseURL
const staticURL = window.FileBrowser.StaticURL
const recaptcha = window.FileBrowser.ReCaptcha
const recaptchaKey = window.FileBrowser.ReCaptchaKey
const signup = window.FileBrowser.Signup
const version = window.FileBrowser.Version
const logoURL = `/${staticURL}/img/logo.svg`
const noAuth = window.FileBrowser.NoAuth
export {
name,
disableExternal,
baseURL,
logoURL,
recaptcha,
recaptchaKey,
signup,
version,
noAuth
}

55
src/utils/vue.js Normal file
View File

@@ -0,0 +1,55 @@
import Vue from 'vue'
import Noty from 'noty'
import i18n from '@/i18n'
import { disableExternal } from '@/utils/constants'
Vue.config.productionTip = true
const notyDefault = {
type: 'info',
layout: 'bottomRight',
timeout: 1000,
progressBar: true
}
Vue.prototype.$noty = (opts) => {
new Noty(Object.assign({}, notyDefault, opts)).show()
}
Vue.prototype.$showSuccess = (message) => {
new Noty(Object.assign({}, notyDefault, {
text: message,
type: 'success'
})).show()
}
Vue.prototype.$showError = (error) => {
let btns = [
Noty.button(i18n.t('buttons.close'), '', function () {
n.close()
})
]
if (!disableExternal) {
btns.unshift(Noty.button(i18n.t('buttons.reportIssue'), '', function () {
window.open('https://github.com/filebrowser/filebrowser/issues/new/choose')
}))
}
let n = new Noty(Object.assign({}, notyDefault, {
text: error.message || error,
type: 'error',
timeout: null,
buttons: btns
}))
n.show()
}
Vue.directive('focus', {
inserted: function (el) {
el.focus()
}
})
export default Vue