commit
dee465ab86
|
@ -50,6 +50,7 @@ type FileOptions struct {
|
||||||
ReadHeader bool
|
ReadHeader bool
|
||||||
Token string
|
Token string
|
||||||
Checker rules.Checker
|
Checker rules.Checker
|
||||||
|
Content bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileInfo creates a File object from a path and a given user. This File
|
// NewFileInfo creates a File object from a path and a given user. This File
|
||||||
|
@ -85,7 +86,7 @@ func NewFileInfo(opts FileOptions) (*FileInfo, error) {
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = file.detectType(opts.Modify, true, true)
|
err = file.detectType(opts.Modify, opts.Content, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"ace-builds": "^1.4.7",
|
"ace-builds": "^1.4.7",
|
||||||
"clipboard": "^2.0.4",
|
"clipboard": "^2.0.4",
|
||||||
"core-js": "^3.9.1",
|
"core-js": "^3.9.1",
|
||||||
|
"css-vars-ponyfill": "^2.4.3",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
|
@ -25,7 +26,8 @@
|
||||||
"vue-lazyload": "^1.3.3",
|
"vue-lazyload": "^1.3.3",
|
||||||
"vue-router": "^3.1.3",
|
"vue-router": "^3.1.3",
|
||||||
"vuex": "^3.1.2",
|
"vuex": "^3.1.2",
|
||||||
"vuex-router-sync": "^5.0.0"
|
"vuex-router-sync": "^5.0.0",
|
||||||
|
"whatwg-fetch": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^4.1.2",
|
"@vue/cli-plugin-babel": "^4.1.2",
|
||||||
|
@ -33,6 +35,7 @@
|
||||||
"@vue/cli-service": "^4.1.2",
|
"@vue/cli-service": "^4.1.2",
|
||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
|
"compression-webpack-plugin": "^6.0.3",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
"eslint-plugin-prettier": "^3.3.1",
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
"eslint-plugin-vue": "^6.2.2",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
@ -1383,6 +1386,46 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@npmcli/move-file": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mkdirp": "^1.0.4",
|
||||||
|
"rimraf": "^3.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@npmcli/move-file/node_modules/mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"mkdirp": "bin/cmd.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@npmcli/move-file/node_modules/rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@soda/friendly-errors-webpack-plugin": {
|
"node_modules/@soda/friendly-errors-webpack-plugin": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz",
|
||||||
|
@ -4092,6 +4135,165 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/compression-webpack-plugin": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-xzSWiZWwBs+HHGhlYxw0oFaYL/0VYErEqDHCAJhJ3Mza5fmF5JJ4iaB6Ap2JT68C0UhhmoI4Mh37LVz/THv2Fw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cacache": "^15.0.5",
|
||||||
|
"find-cache-dir": "^3.3.1",
|
||||||
|
"schema-utils": "^3.0.0",
|
||||||
|
"serialize-javascript": "^5.0.1",
|
||||||
|
"webpack-sources": "^1.4.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/webpack"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"webpack": "^4.0.0 || ^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/cacache": {
|
||||||
|
"version": "15.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.6.tgz",
|
||||||
|
"integrity": "sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@npmcli/move-file": "^1.0.1",
|
||||||
|
"chownr": "^2.0.0",
|
||||||
|
"fs-minipass": "^2.0.0",
|
||||||
|
"glob": "^7.1.4",
|
||||||
|
"infer-owner": "^1.0.4",
|
||||||
|
"lru-cache": "^6.0.0",
|
||||||
|
"minipass": "^3.1.1",
|
||||||
|
"minipass-collect": "^1.0.2",
|
||||||
|
"minipass-flush": "^1.0.5",
|
||||||
|
"minipass-pipeline": "^1.2.2",
|
||||||
|
"mkdirp": "^1.0.3",
|
||||||
|
"p-map": "^4.0.0",
|
||||||
|
"promise-inflight": "^1.0.1",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"ssri": "^8.0.1",
|
||||||
|
"tar": "^6.0.2",
|
||||||
|
"unique-filename": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/chownr": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"mkdirp": "bin/cmd.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/p-map": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"aggregate-error": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/schema-utils": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/json-schema": "^7.0.6",
|
||||||
|
"ajv": "^6.12.5",
|
||||||
|
"ajv-keywords": "^3.5.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/webpack"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/serialize-javascript": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"randombytes": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/ssri": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^3.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/compression/node_modules/bytes": {
|
"node_modules/compression/node_modules/bytes": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||||
|
@ -4663,6 +4865,11 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-vars-ponyfill": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-vars-ponyfill/-/css-vars-ponyfill-2.4.3.tgz",
|
||||||
|
"integrity": "sha512-PBfIwjSu27s8kebu8taEYFM8ehVr8o2Qw4H4nSlJzHAJgcduAqxz4oPmYTJuzgauOKaWII9SHWStQ965fxsdZA=="
|
||||||
|
},
|
||||||
"node_modules/css-what": {
|
"node_modules/css-what": {
|
||||||
"version": "3.4.2",
|
"version": "3.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
||||||
|
@ -9045,6 +9252,25 @@
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/minizlib": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^3.0.0",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minizlib/node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/mississippi": {
|
"node_modules/mississippi": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
||||||
|
@ -12746,6 +12972,50 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tar": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"chownr": "^2.0.0",
|
||||||
|
"fs-minipass": "^2.0.0",
|
||||||
|
"minipass": "^3.0.0",
|
||||||
|
"minizlib": "^2.1.1",
|
||||||
|
"mkdirp": "^1.0.3",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar/node_modules/chownr": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar/node_modules/mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"mkdirp": "bin/cmd.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar/node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "4.8.0",
|
"version": "4.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
||||||
|
@ -14709,6 +14979,11 @@
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/whatwg-fetch": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA=="
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||||
|
@ -16234,6 +16509,33 @@
|
||||||
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
|
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@npmcli/move-file": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"mkdirp": "^1.0.4",
|
||||||
|
"rimraf": "^3.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@soda/friendly-errors-webpack-plugin": {
|
"@soda/friendly-errors-webpack-plugin": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz",
|
||||||
|
@ -18503,6 +18805,120 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"compression-webpack-plugin": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-xzSWiZWwBs+HHGhlYxw0oFaYL/0VYErEqDHCAJhJ3Mza5fmF5JJ4iaB6Ap2JT68C0UhhmoI4Mh37LVz/THv2Fw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"cacache": "^15.0.5",
|
||||||
|
"find-cache-dir": "^3.3.1",
|
||||||
|
"schema-utils": "^3.0.0",
|
||||||
|
"serialize-javascript": "^5.0.1",
|
||||||
|
"webpack-sources": "^1.4.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cacache": {
|
||||||
|
"version": "15.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.6.tgz",
|
||||||
|
"integrity": "sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@npmcli/move-file": "^1.0.1",
|
||||||
|
"chownr": "^2.0.0",
|
||||||
|
"fs-minipass": "^2.0.0",
|
||||||
|
"glob": "^7.1.4",
|
||||||
|
"infer-owner": "^1.0.4",
|
||||||
|
"lru-cache": "^6.0.0",
|
||||||
|
"minipass": "^3.1.1",
|
||||||
|
"minipass-collect": "^1.0.2",
|
||||||
|
"minipass-flush": "^1.0.5",
|
||||||
|
"minipass-pipeline": "^1.2.2",
|
||||||
|
"mkdirp": "^1.0.3",
|
||||||
|
"p-map": "^4.0.0",
|
||||||
|
"promise-inflight": "^1.0.1",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"ssri": "^8.0.1",
|
||||||
|
"tar": "^6.0.2",
|
||||||
|
"unique-filename": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chownr": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"p-map": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"aggregate-error": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema-utils": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/json-schema": "^7.0.6",
|
||||||
|
"ajv": "^6.12.5",
|
||||||
|
"ajv-keywords": "^3.5.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serialize-javascript": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"randombytes": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ssri": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"minipass": "^3.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
|
@ -18948,6 +19364,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"css-vars-ponyfill": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-vars-ponyfill/-/css-vars-ponyfill-2.4.3.tgz",
|
||||||
|
"integrity": "sha512-PBfIwjSu27s8kebu8taEYFM8ehVr8o2Qw4H4nSlJzHAJgcduAqxz4oPmYTJuzgauOKaWII9SHWStQ965fxsdZA=="
|
||||||
|
},
|
||||||
"css-what": {
|
"css-what": {
|
||||||
"version": "3.4.2",
|
"version": "3.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
||||||
|
@ -22407,6 +22828,24 @@
|
||||||
"minipass": "^3.0.0"
|
"minipass": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"minizlib": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"minipass": "^3.0.0",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"mississippi": {
|
"mississippi": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
||||||
|
@ -25512,6 +25951,40 @@
|
||||||
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
|
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"tar": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chownr": "^2.0.0",
|
||||||
|
"fs-minipass": "^2.0.0",
|
||||||
|
"minipass": "^3.0.0",
|
||||||
|
"minizlib": "^2.1.1",
|
||||||
|
"mkdirp": "^1.0.3",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"chownr": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"version": "4.8.0",
|
"version": "4.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
||||||
|
@ -27088,6 +27561,11 @@
|
||||||
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
|
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"whatwg-fetch": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA=="
|
||||||
|
},
|
||||||
"which": {
|
"which": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"ace-builds": "^1.4.7",
|
"ace-builds": "^1.4.7",
|
||||||
"clipboard": "^2.0.4",
|
"clipboard": "^2.0.4",
|
||||||
"core-js": "^3.9.1",
|
"core-js": "^3.9.1",
|
||||||
|
"css-vars-ponyfill": "^2.4.3",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
|
@ -27,7 +28,8 @@
|
||||||
"vue-lazyload": "^1.3.3",
|
"vue-lazyload": "^1.3.3",
|
||||||
"vue-router": "^3.1.3",
|
"vue-router": "^3.1.3",
|
||||||
"vuex": "^3.1.2",
|
"vuex": "^3.1.2",
|
||||||
"vuex-router-sync": "^5.0.0"
|
"vuex-router-sync": "^5.0.0",
|
||||||
|
"whatwg-fetch": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^4.1.2",
|
"@vue/cli-plugin-babel": "^4.1.2",
|
||||||
|
@ -35,6 +37,7 @@
|
||||||
"@vue/cli-service": "^4.1.2",
|
"@vue/cli-service": "^4.1.2",
|
||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
|
"compression-webpack-plugin": "^6.0.3",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
"eslint-plugin-prettier": "^3.3.1",
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
"eslint-plugin-vue": "^6.2.2",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
@ -64,6 +67,6 @@
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions",
|
"last 2 versions",
|
||||||
"not ie <= 8"
|
"not ie < 11"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
<!-- Inject Some Variables and generate the manifest json -->
|
<!-- Inject Some Variables and generate the manifest json -->
|
||||||
<script>
|
<script>
|
||||||
window.FileBrowser = JSON.parse(`[{[ .Json ]}]`);
|
window.FileBrowser = JSON.parse('[{[ .Json ]}]');
|
||||||
|
|
||||||
var fullStaticURL = window.location.origin + window.FileBrowser.StaticURL;
|
var fullStaticURL = window.location.origin + window.FileBrowser.StaticURL;
|
||||||
var dynamicManifest = {
|
var dynamicManifest = {
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner {
|
#loading .spinner {
|
||||||
width: 70px;
|
width: 70px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner > div {
|
#loading .spinner > div {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
|
@ -97,12 +97,12 @@
|
||||||
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner .bounce1 {
|
#loading .spinner .bounce1 {
|
||||||
-webkit-animation-delay: -0.32s;
|
-webkit-animation-delay: -0.32s;
|
||||||
animation-delay: -0.32s;
|
animation-delay: -0.32s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner .bounce2 {
|
#loading .spinner .bounce2 {
|
||||||
-webkit-animation-delay: -0.16s;
|
-webkit-animation-delay: -0.16s;
|
||||||
animation-delay: -0.16s;
|
animation-delay: -0.16s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ body {
|
||||||
#loading {
|
#loading {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
}
|
}
|
||||||
#loading .spinner div, #previewer .loading .spinner div {
|
#loading .spinner div, main .spinner div {
|
||||||
background: var(--icon);
|
background: var(--icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
__webpack_public_path__ = window.FileBrowser.StaticURL + "/";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "app",
|
name: "app",
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
|
@ -8,13 +8,18 @@ export async function fetchURL(url, opts) {
|
||||||
|
|
||||||
let { headers, ...rest } = opts;
|
let { headers, ...rest } = opts;
|
||||||
|
|
||||||
const res = await fetch(`${baseURL}${url}`, {
|
let res;
|
||||||
|
try {
|
||||||
|
res = await fetch(`${baseURL}${url}`, {
|
||||||
headers: {
|
headers: {
|
||||||
"X-Auth": store.state.jwt,
|
"X-Auth": store.state.jwt,
|
||||||
...headers,
|
...headers,
|
||||||
},
|
},
|
||||||
...rest,
|
...rest,
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return { status: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
if (res.headers.get("X-Renew-Token") === "true") {
|
if (res.headers.get("X-Renew-Token") === "true") {
|
||||||
await renew(store.state.jwt);
|
await renew(store.state.jwt);
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
@dragover="dragOver"
|
@dragover="dragOver"
|
||||||
@drop="drop"
|
@drop="drop"
|
||||||
@click="itemClick"
|
@click="itemClick"
|
||||||
@dblclick="dblclick"
|
|
||||||
@touchstart="touchstart"
|
|
||||||
:data-dir="isDir"
|
:data-dir="isDir"
|
||||||
:aria-label="name"
|
:aria-label="name"
|
||||||
:aria-selected="isSelected"
|
:aria-selected="isSelected"
|
||||||
|
@ -96,7 +94,7 @@ export default {
|
||||||
// reload the image when the file is replaced
|
// reload the image when the file is replaced
|
||||||
const key = Date.parse(this.modified);
|
const key = Date.parse(this.modified);
|
||||||
|
|
||||||
return `${baseURL}/api/preview/thumb/${path}?auth=${this.jwt}&inline=true&k=${key}`;
|
return `${baseURL}/api/preview/thumb/${path}?k=${key}&inline=true`;
|
||||||
},
|
},
|
||||||
isThumbsEnabled() {
|
isThumbsEnabled() {
|
||||||
return enableThumbs;
|
return enableThumbs;
|
||||||
|
@ -153,13 +151,13 @@ export default {
|
||||||
for (let i of this.selected) {
|
for (let i of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[i].url,
|
from: this.req.items[i].url,
|
||||||
to: this.url + this.req.items[i].name,
|
to: this.url + encodeURIComponent(this.req.items[i].name),
|
||||||
name: this.req.items[i].name,
|
name: this.req.items[i].name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let base = el.querySelector(".name").innerHTML + "/";
|
// Get url from ListingItem instance
|
||||||
let path = this.$route.path + base;
|
let path = el.__vue__.url;
|
||||||
let baseItems = (await api.fetch(path)).items;
|
let baseItems = (await api.fetch(path)).items;
|
||||||
|
|
||||||
let action = (overwrite, rename) => {
|
let action = (overwrite, rename) => {
|
||||||
|
@ -200,6 +198,16 @@ export default {
|
||||||
},
|
},
|
||||||
click: function (event) {
|
click: function (event) {
|
||||||
if (!this.singleClick && this.selectedCount !== 0) event.preventDefault();
|
if (!this.singleClick && this.selectedCount !== 0) event.preventDefault();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.touches = 0;
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
this.touches++;
|
||||||
|
if (this.touches > 1) {
|
||||||
|
this.open();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.$store.state.selected.indexOf(this.index) !== -1) {
|
if (this.$store.state.selected.indexOf(this.index) !== -1) {
|
||||||
this.removeSelected(this.index);
|
this.removeSelected(this.index);
|
||||||
return;
|
return;
|
||||||
|
@ -235,19 +243,6 @@ export default {
|
||||||
this.resetSelected();
|
this.resetSelected();
|
||||||
this.addSelected(this.index);
|
this.addSelected(this.index);
|
||||||
},
|
},
|
||||||
dblclick: function () {
|
|
||||||
if (!this.singleClick) this.open();
|
|
||||||
},
|
|
||||||
touchstart() {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.touches = 0;
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
this.touches++;
|
|
||||||
if (this.touches > 1) {
|
|
||||||
this.open();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
open: function () {
|
open: function () {
|
||||||
this.$router.push({ path: this.url });
|
this.$router.push({ path: this.url });
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<strong>{{ $t("prompts.size") }}:</strong>
|
<strong>{{ $t("prompts.size") }}:</strong>
|
||||||
<span id="content_length"></span> {{ humanSize }}
|
<span id="content_length"></span> {{ humanSize }}
|
||||||
</p>
|
</p>
|
||||||
<p v-if="selected.length < 2">
|
<p v-if="selected.length < 2" :title="modTime">
|
||||||
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -110,6 +110,9 @@ export default {
|
||||||
|
|
||||||
return moment(this.req.items[this.selected[0]].modified).fromNow();
|
return moment(this.req.items[this.selected[0]].modified).fromNow();
|
||||||
},
|
},
|
||||||
|
modTime: function () {
|
||||||
|
return new Date(Date.parse(this.req.modified)).toLocaleString();
|
||||||
|
},
|
||||||
name: function () {
|
name: function () {
|
||||||
return this.selectedCount === 0
|
return this.selectedCount === 0
|
||||||
? this.req.name
|
? this.req.name
|
||||||
|
|
|
@ -43,6 +43,15 @@
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.share__box__element .button {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box__element .button i {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.share__box__items {
|
.share__box__items {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
flex: 10 0 25em;
|
flex: 10 0 25em;
|
||||||
|
|
|
@ -17,6 +17,48 @@
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main .spinner {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 0;
|
||||||
|
padding: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
main .spinner > div {
|
||||||
|
width: .8em;
|
||||||
|
height: .8em;
|
||||||
|
margin: 0 .1em;
|
||||||
|
font-size: 1em;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||||
|
}
|
||||||
|
|
||||||
|
main .spinner .bounce1 {
|
||||||
|
animation-delay: -0.32s;
|
||||||
|
}
|
||||||
|
|
||||||
|
main .spinner .bounce2 {
|
||||||
|
animation-delay: -0.16s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delayed {
|
||||||
|
animation: delayed linear 100ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes delayed {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
99% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * *
|
||||||
* ACTION *
|
* ACTION *
|
||||||
* * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * */
|
||||||
|
@ -204,6 +246,20 @@
|
||||||
right: 0.5em;
|
right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#previewer .spinner {
|
||||||
|
text-align: center;
|
||||||
|
position: fixed;
|
||||||
|
top: calc(50% + 1.85em);
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer .spinner > div {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* EDITOR */
|
/* EDITOR */
|
||||||
|
|
||||||
#editor-container {
|
#editor-container {
|
||||||
|
@ -217,11 +273,6 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .loading {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#editor-container #editor {
|
#editor-container #editor {
|
||||||
height: calc(100vh - 8.4em);
|
height: calc(100vh - 8.4em);
|
||||||
}
|
}
|
||||||
|
@ -283,7 +334,6 @@
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
100% {
|
100% {
|
||||||
-webkit-transform: rotate(-360deg);
|
|
||||||
transform: rotate(-360deg);
|
transform: rotate(-360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,8 @@
|
||||||
"switchView": "Switch view",
|
"switchView": "Switch view",
|
||||||
"toggleSidebar": "Toggle sidebar",
|
"toggleSidebar": "Toggle sidebar",
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
"upload": "Upload"
|
"upload": "Upload",
|
||||||
|
"openFile": "Open file"
|
||||||
},
|
},
|
||||||
"download": {
|
"download": {
|
||||||
"downloadFile": "Download File",
|
"downloadFile": "Download File",
|
||||||
|
@ -43,7 +44,8 @@
|
||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "You don't have permissions to access this.",
|
"forbidden": "You don't have permissions to access this.",
|
||||||
"internal": "Something really went wrong.",
|
"internal": "Something really went wrong.",
|
||||||
"notFound": "This location can't be reached."
|
"notFound": "This location can't be reached.",
|
||||||
|
"connection": "The server can't be reached."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"body": "Body",
|
"body": "Body",
|
||||||
|
@ -214,6 +216,7 @@
|
||||||
"settingsUpdated": "Settings updated!",
|
"settingsUpdated": "Settings updated!",
|
||||||
"shareDuration": "Share Duration",
|
"shareDuration": "Share Duration",
|
||||||
"shareManagement": "Share Management",
|
"shareManagement": "Share Management",
|
||||||
|
"shareDeleted": "Share deleted!",
|
||||||
"singleClick": "Use single clicks to open files and directories",
|
"singleClick": "Use single clicks to open files and directories",
|
||||||
"themes": {
|
"themes": {
|
||||||
"dark": "Dark",
|
"dark": "Dark",
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import "whatwg-fetch";
|
||||||
|
import cssVars from "css-vars-ponyfill";
|
||||||
import { sync } from "vuex-router-sync";
|
import { sync } from "vuex-router-sync";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
|
@ -7,6 +9,8 @@ import { recaptcha, loginPage } from "@/utils/constants";
|
||||||
import { login, validateLogin } from "@/utils/auth";
|
import { login, validateLogin } from "@/utils/auth";
|
||||||
import App from "@/App";
|
import App from "@/App";
|
||||||
|
|
||||||
|
cssVars();
|
||||||
|
|
||||||
sync(store, router);
|
sync(store, router);
|
||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
|
|
|
@ -12,6 +12,8 @@ export function parseToken(token) {
|
||||||
|
|
||||||
const data = JSON.parse(Base64.decode(parts[1]));
|
const data = JSON.parse(Base64.decode(parts[1]));
|
||||||
|
|
||||||
|
document.cookie = `auth=${token}; path=/`;
|
||||||
|
|
||||||
localStorage.setItem("jwt", token);
|
localStorage.setItem("jwt", token);
|
||||||
store.commit("setJWT", token);
|
store.commit("setJWT", token);
|
||||||
store.commit("setUser", data.user);
|
store.commit("setUser", data.user);
|
||||||
|
@ -81,6 +83,8 @@ export async function signup(username, password) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logout() {
|
export function logout() {
|
||||||
|
document.cookie = "auth=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/";
|
||||||
|
|
||||||
store.commit("setJWT", "");
|
store.commit("setJWT", "");
|
||||||
store.commit("setUser", null);
|
store.commit("setUser", null);
|
||||||
localStorage.setItem("jwt", null);
|
localStorage.setItem("jwt", null);
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
<header-bar v-if="showHeader" showMenu showLogo />
|
<header-bar v-if="showHeader" showMenu showLogo />
|
||||||
|
|
||||||
<h2 class="message">
|
<h2 class="message">
|
||||||
<i class="material-icons">{{ icon }}</i>
|
<i class="material-icons">{{ info.icon }}</i>
|
||||||
<span>{{ message }}</span>
|
<span>{{ $t(info.message) }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -13,6 +13,10 @@
|
||||||
import HeaderBar from "@/components/header/HeaderBar";
|
import HeaderBar from "@/components/header/HeaderBar";
|
||||||
|
|
||||||
const errors = {
|
const errors = {
|
||||||
|
0: {
|
||||||
|
icon: "cloud_off",
|
||||||
|
message: "errors.connection",
|
||||||
|
},
|
||||||
403: {
|
403: {
|
||||||
icon: "error",
|
icon: "error",
|
||||||
message: "errors.forbidden",
|
message: "errors.forbidden",
|
||||||
|
@ -33,11 +37,17 @@ export default {
|
||||||
HeaderBar,
|
HeaderBar,
|
||||||
},
|
},
|
||||||
props: ["errorCode", "showHeader"],
|
props: ["errorCode", "showHeader"],
|
||||||
data: function () {
|
computed: {
|
||||||
return {
|
code() {
|
||||||
icon: errors[this.errorCode].icon,
|
return this.errorCode === "0" ||
|
||||||
message: this.$t(errors[this.errorCode].message),
|
this.errorCode === "404" ||
|
||||||
};
|
this.errorCode === "403"
|
||||||
|
? parseInt(this.errorCode)
|
||||||
|
: 500;
|
||||||
|
},
|
||||||
|
info() {
|
||||||
|
return errors[this.code];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -4,10 +4,15 @@
|
||||||
|
|
||||||
<breadcrumbs base="/files" />
|
<breadcrumbs base="/files" />
|
||||||
|
|
||||||
<errors v-if="error" :errorCode="errorCode" />
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
<component v-else-if="currentView" :is="currentView"></component>
|
<component v-else-if="currentView" :is="currentView"></component>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h2 class="message">
|
<h2 class="message delayed">
|
||||||
|
<div class="spinner">
|
||||||
|
<div class="bounce1"></div>
|
||||||
|
<div class="bounce2"></div>
|
||||||
|
<div class="bounce3"></div>
|
||||||
|
</div>
|
||||||
<span>{{ $t("files.loading") }}</span>
|
<span>{{ $t("files.loading") }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,11 +67,6 @@ export default {
|
||||||
return "preview";
|
return "preview";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
errorCode() {
|
|
||||||
return this.error.message === "404" || this.error.message === "403"
|
|
||||||
? parseInt(this.error.message)
|
|
||||||
: 500;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.fetchData();
|
this.fetchData();
|
||||||
|
@ -116,7 +116,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.commit("updateRequest", res);
|
this.$store.commit("updateRequest", res);
|
||||||
document.title = res.name;
|
document.title = `${res.name} - ${this.$route.name}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e;
|
this.error = e;
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -34,6 +34,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loading">
|
||||||
|
<h2 class="message delayed">
|
||||||
|
<div class="spinner">
|
||||||
|
<div class="bounce1"></div>
|
||||||
|
<div class="bounce2"></div>
|
||||||
|
<div class="bounce3"></div>
|
||||||
|
</div>
|
||||||
|
<span>{{ $t("files.loading") }}</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -49,7 +60,7 @@ export default {
|
||||||
HeaderBar,
|
HeaderBar,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["user"]),
|
...mapState(["user", "loading"]),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -19,7 +19,50 @@
|
||||||
|
|
||||||
<breadcrumbs :base="'/share/' + hash" />
|
<breadcrumbs :base="'/share/' + hash" />
|
||||||
|
|
||||||
<div v-if="!loading">
|
<div v-if="loading">
|
||||||
|
<h2 class="message delayed">
|
||||||
|
<div class="spinner">
|
||||||
|
<div class="bounce1"></div>
|
||||||
|
<div class="bounce2"></div>
|
||||||
|
<div class="bounce3"></div>
|
||||||
|
</div>
|
||||||
|
<span>{{ $t("files.loading") }}</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="error">
|
||||||
|
<div v-if="error.message === '401'">
|
||||||
|
<div class="card floating" id="password">
|
||||||
|
<div v-if="attemptedPasswordLogin" class="share__wrong__password">
|
||||||
|
{{ $t("login.wrongCredentials") }}
|
||||||
|
</div>
|
||||||
|
<div class="card-title">
|
||||||
|
<h2>{{ $t("login.password") }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<input
|
||||||
|
v-focus
|
||||||
|
type="password"
|
||||||
|
:placeholder="$t('login.password')"
|
||||||
|
v-model="password"
|
||||||
|
@keyup.enter="fetchData"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="card-action">
|
||||||
|
<button
|
||||||
|
class="button button--flat"
|
||||||
|
@click="fetchData"
|
||||||
|
:aria-label="$t('buttons.submit')"
|
||||||
|
:title="$t('buttons.submit')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.submit") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<errors v-else :errorCode="error.message" />
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
<div class="share">
|
<div class="share">
|
||||||
<div class="share__box share__box__info">
|
<div class="share__box share__box__info">
|
||||||
<div class="share__box__header">
|
<div class="share__box__header">
|
||||||
|
@ -35,16 +78,30 @@
|
||||||
<div class="share__box__element">
|
<div class="share__box__element">
|
||||||
<strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
|
<strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element">
|
<div class="share__box__element" :title="modTime">
|
||||||
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element">
|
<div class="share__box__element">
|
||||||
<strong>{{ $t("prompts.size") }}:</strong> {{ humanSize }}
|
<strong>{{ $t("prompts.size") }}:</strong> {{ humanSize }}
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element share__box__center">
|
<div class="share__box__element share__box__center">
|
||||||
<a target="_blank" :href="link" class="button button--flat">{{
|
<a target="_blank" :href="link" class="button button--flat">
|
||||||
$t("buttons.download")
|
<div>
|
||||||
}}</a>
|
<i class="material-icons">file_download</i
|
||||||
|
>{{ $t("buttons.download") }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
:href="link + '?inline=true'"
|
||||||
|
class="button button--flat"
|
||||||
|
v-if="!req.isDir"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<i class="material-icons">open_in_new</i
|
||||||
|
>{{ $t("buttons.openFile") }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element share__box__center">
|
<div class="share__box__element share__box__center">
|
||||||
<qrcode-vue :value="fullLink" size="200" level="M"></qrcode-vue>
|
<qrcode-vue :value="fullLink" size="200" level="M"></qrcode-vue>
|
||||||
|
@ -71,7 +128,11 @@
|
||||||
readOnly
|
readOnly
|
||||||
>
|
>
|
||||||
</item>
|
</item>
|
||||||
<div v-if="req.items.length > showLimit" class="item">
|
<div
|
||||||
|
v-if="req.items.length > showLimit"
|
||||||
|
class="item"
|
||||||
|
@click="showLimit += 100"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<p class="name">+ {{ req.items.length - showLimit }}</p>
|
<p class="name">+ {{ req.items.length - showLimit }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -106,39 +167,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="error">
|
|
||||||
<div v-if="error.message === '401'">
|
|
||||||
<div class="card floating" id="password">
|
|
||||||
<div v-if="attemptedPasswordLogin" class="share__wrong__password">
|
|
||||||
{{ $t("login.wrongCredentials") }}
|
|
||||||
</div>
|
|
||||||
<div class="card-title">
|
|
||||||
<h2>{{ $t("login.password") }}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-content">
|
|
||||||
<input
|
|
||||||
v-focus
|
|
||||||
type="password"
|
|
||||||
:placeholder="$t('login.password')"
|
|
||||||
v-model="password"
|
|
||||||
@keyup.enter="fetchData"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="card-action">
|
|
||||||
<button
|
|
||||||
class="button button--flat"
|
|
||||||
@click="fetchData"
|
|
||||||
:aria-label="$t('buttons.submit')"
|
|
||||||
:title="$t('buttons.submit')"
|
|
||||||
>
|
|
||||||
{{ $t("buttons.submit") }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<errors v-else :errorCode="errorCode" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -168,14 +196,18 @@ export default {
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
error: null,
|
error: null,
|
||||||
showLimit: 500,
|
showLimit: 100,
|
||||||
password: "",
|
password: "",
|
||||||
attemptedPasswordLogin: false,
|
attemptedPasswordLogin: false,
|
||||||
hash: null,
|
hash: null,
|
||||||
token: null,
|
token: null,
|
||||||
}),
|
}),
|
||||||
watch: {
|
watch: {
|
||||||
$route: "fetchData",
|
$route: function () {
|
||||||
|
this.showLimit = 100;
|
||||||
|
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created: async function () {
|
created: async function () {
|
||||||
const hash = this.$route.params.pathMatch.split("/")[0];
|
const hash = this.$route.params.pathMatch.split("/")[0];
|
||||||
|
@ -220,10 +252,8 @@ export default {
|
||||||
humanTime: function () {
|
humanTime: function () {
|
||||||
return moment(this.req.modified).fromNow();
|
return moment(this.req.modified).fromNow();
|
||||||
},
|
},
|
||||||
errorCode() {
|
modTime: function () {
|
||||||
return this.error.message === "404" || this.error.message === "403"
|
return new Date(Date.parse(this.req.modified)).toLocaleString();
|
||||||
? parseInt(this.error.message)
|
|
||||||
: 500;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -256,9 +286,11 @@ export default {
|
||||||
this.token = file.token || "";
|
this.token = file.token || "";
|
||||||
|
|
||||||
this.updateRequest(file);
|
this.updateRequest(file);
|
||||||
this.setLoading(false);
|
document.title = `${file.name} - ${this.$route.name}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e;
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
keyEvent(event) {
|
keyEvent(event) {
|
||||||
|
|
|
@ -114,8 +114,13 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="$store.state.loading">
|
<div v-if="loading">
|
||||||
<h2 class="message">
|
<h2 class="message delayed">
|
||||||
|
<div class="spinner">
|
||||||
|
<div class="bounce1"></div>
|
||||||
|
<div class="bounce2"></div>
|
||||||
|
<div class="bounce3"></div>
|
||||||
|
</div>
|
||||||
<span>{{ $t("files.loading") }}</span>
|
<span>{{ $t("files.loading") }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
@ -254,6 +259,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Vue from "vue";
|
||||||
import { mapState, mapGetters, mapMutations } from "vuex";
|
import { mapState, mapGetters, mapMutations } from "vuex";
|
||||||
import { users, files as api } from "@/api";
|
import { users, files as api } from "@/api";
|
||||||
import { enableExec } from "@/utils/constants";
|
import { enableExec } from "@/utils/constants";
|
||||||
|
@ -279,10 +285,19 @@ export default {
|
||||||
showLimit: 50,
|
showLimit: 50,
|
||||||
dragCounter: 0,
|
dragCounter: 0,
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
|
itemWeight: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["req", "selected", "user", "show", "multiple", "selected"]),
|
...mapState([
|
||||||
|
"req",
|
||||||
|
"selected",
|
||||||
|
"user",
|
||||||
|
"show",
|
||||||
|
"multiple",
|
||||||
|
"selected",
|
||||||
|
"loading",
|
||||||
|
]),
|
||||||
...mapGetters(["selectedCount"]),
|
...mapGetters(["selectedCount"]),
|
||||||
nameSorted() {
|
nameSorted() {
|
||||||
return this.req.sorting.by === "name";
|
return this.req.sorting.by === "name";
|
||||||
|
@ -362,8 +377,14 @@ export default {
|
||||||
// Reset the show value
|
// Reset the show value
|
||||||
this.showLimit = 50;
|
this.showLimit = 50;
|
||||||
|
|
||||||
|
// Ensures that the listing is displayed
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
// How much every listing item affects the window height
|
||||||
|
this.setItemWeight();
|
||||||
|
|
||||||
// Fill and fit the window with listing items
|
// Fill and fit the window with listing items
|
||||||
this.fillWindow(true);
|
this.fillWindow(true);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
|
@ -393,7 +414,7 @@ export default {
|
||||||
window.removeEventListener("scroll", this.scrollEvent);
|
window.removeEventListener("scroll", this.scrollEvent);
|
||||||
window.removeEventListener("resize", this.windowsResize);
|
window.removeEventListener("resize", this.windowsResize);
|
||||||
|
|
||||||
if (!this.user.perm.create) return;
|
if (this.user && !this.user.perm.create) return;
|
||||||
document.removeEventListener("dragover", this.preventDefault);
|
document.removeEventListener("dragover", this.preventDefault);
|
||||||
document.removeEventListener("dragenter", this.dragEnter);
|
document.removeEventListener("dragenter", this.dragEnter);
|
||||||
document.removeEventListener("dragleave", this.dragLeave);
|
document.removeEventListener("dragleave", this.dragLeave);
|
||||||
|
@ -484,7 +505,7 @@ export default {
|
||||||
for (let i of this.selected) {
|
for (let i of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[i].url,
|
from: this.req.items[i].url,
|
||||||
name: encodeURIComponent(this.req.items[i].name),
|
name: this.req.items[i].name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,7 +530,7 @@ export default {
|
||||||
const from = item.from.endsWith("/")
|
const from = item.from.endsWith("/")
|
||||||
? item.from.slice(0, -1)
|
? item.from.slice(0, -1)
|
||||||
: item.from;
|
: item.from;
|
||||||
const to = this.$route.path + item.name;
|
const to = this.$route.path + encodeURIComponent(item.name);
|
||||||
items.push({ from, to, name: item.name });
|
items.push({ from, to, name: item.name });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,22 +652,20 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let base = "";
|
let files = await upload.scanFiles(dt);
|
||||||
|
let items = this.req.items;
|
||||||
|
let path = this.$route.path.endsWith("/")
|
||||||
|
? this.$route.path
|
||||||
|
: this.$route.path + "/";
|
||||||
|
|
||||||
if (
|
if (
|
||||||
el !== null &&
|
el !== null &&
|
||||||
el.classList.contains("item") &&
|
el.classList.contains("item") &&
|
||||||
el.dataset.dir === "true"
|
el.dataset.dir === "true"
|
||||||
) {
|
) {
|
||||||
base = el.querySelector(".name").innerHTML + "/";
|
// Get url from ListingItem instance
|
||||||
}
|
path = el.__vue__.url;
|
||||||
|
|
||||||
let files = await upload.scanFiles(dt);
|
|
||||||
let path = this.$route.path.endsWith("/")
|
|
||||||
? this.$route.path + base
|
|
||||||
: this.$route.path + "/" + base;
|
|
||||||
let items = this.req.items;
|
|
||||||
|
|
||||||
if (base !== "") {
|
|
||||||
try {
|
try {
|
||||||
items = (await api.fetch(path)).items;
|
items = (await api.fetch(path)).items;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -793,26 +812,28 @@ export default {
|
||||||
viewMode: this.user.viewMode === "mosaic" ? "list" : "mosaic",
|
viewMode: this.user.viewMode === "mosaic" ? "list" : "mosaic",
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
users.update(data, ["viewMode"]).catch(this.$showError);
|
||||||
await users.update(data, ["viewMode"]);
|
|
||||||
|
|
||||||
// Await ensures correct value for setItemWeight()
|
// Await ensures correct value for setItemWeight()
|
||||||
await this.$store.commit("updateUser", data);
|
await this.$store.commit("updateUser", data);
|
||||||
|
|
||||||
this.setItemWeight();
|
this.setItemWeight();
|
||||||
this.fillWindow();
|
this.fillWindow();
|
||||||
} catch (e) {
|
|
||||||
this.$showError(e);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
upload: function () {
|
upload: function () {
|
||||||
if (typeof DataTransferItem.prototype.webkitGetAsEntry !== "undefined") {
|
if (
|
||||||
|
typeof window.DataTransferItem !== "undefined" &&
|
||||||
|
typeof DataTransferItem.prototype.webkitGetAsEntry !== "undefined"
|
||||||
|
) {
|
||||||
this.$store.commit("showHover", "upload");
|
this.$store.commit("showHover", "upload");
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("upload-input").click();
|
document.getElementById("upload-input").click();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setItemWeight() {
|
setItemWeight() {
|
||||||
|
// Listing element is not displayed
|
||||||
|
if (this.$refs.listing == null) return;
|
||||||
|
|
||||||
let itemQuantity = this.req.numDirs + this.req.numFiles;
|
let itemQuantity = this.req.numDirs + this.req.numFiles;
|
||||||
if (itemQuantity > this.showLimit) itemQuantity = this.showLimit;
|
if (itemQuantity > this.showLimit) itemQuantity = this.showLimit;
|
||||||
|
|
||||||
|
|
|
@ -46,15 +46,14 @@
|
||||||
</template>
|
</template>
|
||||||
</header-bar>
|
</header-bar>
|
||||||
|
|
||||||
<div class="loading" v-if="loading">
|
<div class="loading delayed" v-if="loading">
|
||||||
<div class="spinner">
|
<div class="spinner">
|
||||||
<div class="bounce1"></div>
|
<div class="bounce1"></div>
|
||||||
<div class="bounce2"></div>
|
<div class="bounce2"></div>
|
||||||
<div class="bounce3"></div>
|
<div class="bounce3"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<template v-else>
|
||||||
<template v-if="!loading">
|
|
||||||
<div class="preview">
|
<div class="preview">
|
||||||
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
||||||
<audio
|
<audio
|
||||||
|
@ -176,11 +175,9 @@ export default {
|
||||||
if (this.req.type === "image" && !this.fullSize) {
|
if (this.req.type === "image" && !this.fullSize) {
|
||||||
return `${baseURL}/api/preview/big${url.encodePath(
|
return `${baseURL}/api/preview/big${url.encodePath(
|
||||||
this.req.path
|
this.req.path
|
||||||
)}?auth=${this.jwt}&k=${key}`;
|
)}?k=${key}`;
|
||||||
}
|
}
|
||||||
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${
|
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?k=${key}`;
|
||||||
this.jwt
|
|
||||||
}&k=${key}`;
|
|
||||||
},
|
},
|
||||||
raw() {
|
raw() {
|
||||||
return `${this.previewUrl}&inline=true`;
|
return `${this.previewUrl}&inline=true`;
|
||||||
|
@ -258,7 +255,7 @@ export default {
|
||||||
|
|
||||||
if (this.req.subtitles) {
|
if (this.req.subtitles) {
|
||||||
this.subtitles = this.req.subtitles.map(
|
this.subtitles = this.req.subtitles.map(
|
||||||
(sub) => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`
|
(sub) => `${baseURL}/api/raw${sub}?inline=true`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="row" v-if="settings !== null">
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
|
<div class="row" v-else-if="!loading">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form class="card" @submit.prevent="save">
|
<form class="card" @submit.prevent="save">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
|
@ -170,12 +171,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from "vuex";
|
import { mapState, mapMutations } from "vuex";
|
||||||
import { settings as api } from "@/api";
|
import { settings as api } from "@/api";
|
||||||
|
import { enableExec } from "@/utils/constants";
|
||||||
import UserForm from "@/components/settings/UserForm";
|
import UserForm from "@/components/settings/UserForm";
|
||||||
import Rules from "@/components/settings/Rules";
|
import Rules from "@/components/settings/Rules";
|
||||||
import Themes from "@/components/settings/Themes";
|
import Themes from "@/components/settings/Themes";
|
||||||
import { enableExec } from "@/utils/constants";
|
import Errors from "@/views/Errors";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "settings",
|
name: "settings",
|
||||||
|
@ -183,19 +185,23 @@ export default {
|
||||||
Themes,
|
Themes,
|
||||||
UserForm,
|
UserForm,
|
||||||
Rules,
|
Rules,
|
||||||
|
Errors,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
error: null,
|
||||||
originalSettings: null,
|
originalSettings: null,
|
||||||
settings: null,
|
settings: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["user"]),
|
...mapState(["user", "loading"]),
|
||||||
isExecEnabled: () => enableExec,
|
isExecEnabled: () => enableExec,
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
try {
|
try {
|
||||||
|
this.setLoading(true);
|
||||||
|
|
||||||
const original = await api.get();
|
const original = await api.get();
|
||||||
let settings = { ...original, commands: [] };
|
let settings = { ...original, commands: [] };
|
||||||
|
|
||||||
|
@ -211,10 +217,13 @@ export default {
|
||||||
this.originalSettings = original;
|
this.originalSettings = original;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e);
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapMutations(["setLoading"]),
|
||||||
capitalize(name, where = "_") {
|
capitalize(name, where = "_") {
|
||||||
if (where === "caps") where = /(?=[A-Z])/;
|
if (where === "caps") where = /(?=[A-Z])/;
|
||||||
let splitted = name.split(where);
|
let splitted = name.split(where);
|
||||||
|
|
|
@ -103,12 +103,13 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
this.setLoading(false);
|
||||||
this.locale = this.user.locale;
|
this.locale = this.user.locale;
|
||||||
this.hideDotfiles = this.user.hideDotfiles;
|
this.hideDotfiles = this.user.hideDotfiles;
|
||||||
this.singleClick = this.user.singleClick;
|
this.singleClick = this.user.singleClick;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(["updateUser"]),
|
...mapMutations(["updateUser", "setLoading"]),
|
||||||
async updatePassword(event) {
|
async updatePassword(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
|
<div class="row" v-else-if="!loading">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t("settings.shareManagement") }}</h2>
|
<h2>{{ $t("settings.shareManagement") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content full">
|
<div class="card-content full" v-if="links.length > 0">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ $t("settings.path") }}</th>
|
<th>{{ $t("settings.path") }}</th>
|
||||||
|
@ -52,6 +53,10 @@
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<h2 class="message" v-else>
|
||||||
|
<i class="material-icons">sentiment_dissatisfied</i>
|
||||||
|
<span>{{ $t("files.lonely") }}</span>
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,21 +64,28 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { share as api, users } from "@/api";
|
import { share as api, users } from "@/api";
|
||||||
import moment from "moment";
|
|
||||||
import { baseURL } from "@/utils/constants";
|
import { baseURL } from "@/utils/constants";
|
||||||
|
import { mapState, mapMutations } from "vuex";
|
||||||
|
import moment from "moment";
|
||||||
import Clipboard from "clipboard";
|
import Clipboard from "clipboard";
|
||||||
import { mapState } from "vuex";
|
import Errors from "@/views/Errors";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "shares",
|
name: "shares",
|
||||||
computed: mapState(["user"]),
|
components: {
|
||||||
|
Errors,
|
||||||
|
},
|
||||||
|
computed: mapState(["user", "loading"]),
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
error: null,
|
||||||
links: [],
|
links: [],
|
||||||
clip: null,
|
clip: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
|
this.setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let links = await api.list();
|
let links = await api.list();
|
||||||
if (this.user.perm.admin) {
|
if (this.user.perm.admin) {
|
||||||
|
@ -87,7 +99,9 @@ export default {
|
||||||
}
|
}
|
||||||
this.links = links;
|
this.links = links;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e);
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -100,6 +114,7 @@ export default {
|
||||||
this.clip.destroy();
|
this.clip.destroy();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapMutations(["setLoading"]),
|
||||||
deleteLink: async function (event, link) {
|
deleteLink: async function (event, link) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
@ -108,8 +123,13 @@ export default {
|
||||||
confirm: () => {
|
confirm: () => {
|
||||||
this.$store.commit("closeHovers");
|
this.$store.commit("closeHovers");
|
||||||
|
|
||||||
|
try {
|
||||||
api.remove(link.hash);
|
api.remove(link.hash);
|
||||||
this.links = this.links.filter((item) => item.hash !== link.hash);
|
this.links = this.links.filter((item) => item.hash !== link.hash);
|
||||||
|
this.$showSuccess(this.$t("settings.shareDeleted"));
|
||||||
|
} catch (e) {
|
||||||
|
this.$showError(e);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
|
<div class="row" v-else-if="!loading">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form v-if="loaded" @submit="save" class="card">
|
<form @submit="save" class="card">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2 v-if="user.id === 0">{{ $t("settings.newUser") }}</h2>
|
<h2 v-if="user.id === 0">{{ $t("settings.newUser") }}</h2>
|
||||||
<h2 v-else>{{ $t("settings.user") }} {{ user.username }}</h2>
|
<h2 v-else>{{ $t("settings.user") }} {{ user.username }}</h2>
|
||||||
|
@ -55,21 +56,23 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapMutations } from "vuex";
|
import { mapState, mapMutations } from "vuex";
|
||||||
import { users as api, settings } from "@/api";
|
import { users as api, settings } from "@/api";
|
||||||
import UserForm from "@/components/settings/UserForm";
|
import UserForm from "@/components/settings/UserForm";
|
||||||
|
import Errors from "@/views/Errors";
|
||||||
import deepClone from "lodash.clonedeep";
|
import deepClone from "lodash.clonedeep";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "user",
|
name: "user",
|
||||||
components: {
|
components: {
|
||||||
UserForm,
|
UserForm,
|
||||||
|
Errors,
|
||||||
},
|
},
|
||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
|
error: null,
|
||||||
originalUser: null,
|
originalUser: null,
|
||||||
user: {},
|
user: {},
|
||||||
loaded: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
@ -79,6 +82,7 @@ export default {
|
||||||
isNew() {
|
isNew() {
|
||||||
return this.$route.path === "/settings/users/new";
|
return this.$route.path === "/settings/users/new";
|
||||||
},
|
},
|
||||||
|
...mapState(["loading"]),
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route: "fetchData",
|
$route: "fetchData",
|
||||||
|
@ -88,8 +92,10 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(["closeHovers", "showHover", "setUser"]),
|
...mapMutations(["closeHovers", "showHover", "setUser", "setLoading"]),
|
||||||
async fetchData() {
|
async fetchData() {
|
||||||
|
this.setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this.isNew) {
|
if (this.isNew) {
|
||||||
let { defaults } = await settings.get();
|
let { defaults } = await settings.get();
|
||||||
|
@ -105,10 +111,10 @@ export default {
|
||||||
const id = this.$route.params.pathMatch;
|
const id = this.$route.params.pathMatch;
|
||||||
this.user = { ...(await api.get(id)) };
|
this.user = { ...(await api.get(id)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loaded = true;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$router.push({ path: "/settings/users/new" });
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deletePrompt() {
|
deletePrompt() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
|
<div class="row" v-else-if="!loading">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
|
@ -41,21 +42,37 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapState, mapMutations } from "vuex";
|
||||||
import { users as api } from "@/api";
|
import { users as api } from "@/api";
|
||||||
|
import Errors from "@/views/Errors";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "users",
|
name: "users",
|
||||||
|
components: {
|
||||||
|
Errors,
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
error: null,
|
||||||
users: [],
|
users: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
|
this.setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.users = await api.getAll();
|
this.users = await api.getAll();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e);
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["loading"]),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations(["setLoading"]),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
|
const CompressionPlugin = require("compression-webpack-plugin");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
runtimeCompiler: true,
|
runtimeCompiler: true,
|
||||||
publicPath: "[{[ .StaticURL ]}]",
|
publicPath: "[{[ .StaticURL ]}]",
|
||||||
parallel: 2,
|
parallel: 2,
|
||||||
|
configureWebpack: {
|
||||||
|
plugins: [
|
||||||
|
new CompressionPlugin({
|
||||||
|
include: /\.js$/,
|
||||||
|
deleteOriginalAssets: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
11
http/auth.go
11
http/auth.go
|
@ -48,11 +48,16 @@ func (e extractor) ExtractToken(r *http.Request) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auth := r.URL.Query().Get("auth")
|
auth := r.URL.Query().Get("auth")
|
||||||
if auth == "" {
|
if auth != "" && strings.Count(auth, ".") == 2 {
|
||||||
return "", request.ErrNoTokenInRequest
|
return auth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return auth, nil
|
cookie, _ := r.Cookie("auth")
|
||||||
|
if cookie != nil && strings.Count(cookie.Value, ".") == 2 {
|
||||||
|
return cookie.Value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", request.ErrNoTokenInRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUser(fn handleFunc) handleFunc {
|
func withUser(fn handleFunc) handleFunc {
|
||||||
|
|
|
@ -49,6 +49,8 @@ func (d *data) Check(path string) bool {
|
||||||
|
|
||||||
func handle(fn handleFunc, prefix string, store *storage.Storage, server *settings.Server) http.Handler {
|
func handle(fn handleFunc, prefix string, store *storage.Storage, server *settings.Server) http.Handler {
|
||||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
|
||||||
settings, err := store.Settings.Get()
|
settings, err := store.Settings.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("ERROR: couldn't get settings: %v\n", err)
|
log.Fatalf("ERROR: couldn't get settings: %v\n", err)
|
||||||
|
|
|
@ -57,7 +57,7 @@ func NewHandler(
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourceDeleteHandler(fileCache), "/api/resources")).Methods("DELETE")
|
api.PathPrefix("/resources").Handler(monkey(resourceDeleteHandler(fileCache), "/api/resources")).Methods("DELETE")
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourcePostHandler(fileCache), "/api/resources")).Methods("POST")
|
api.PathPrefix("/resources").Handler(monkey(resourcePostHandler(fileCache), "/api/resources")).Methods("POST")
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourcePutHandler, "/api/resources")).Methods("PUT")
|
api.PathPrefix("/resources").Handler(monkey(resourcePutHandler, "/api/resources")).Methods("PUT")
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler, "/api/resources")).Methods("PATCH")
|
api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler(fileCache), "/api/resources")).Methods("PATCH")
|
||||||
|
|
||||||
api.Path("/shares").Handler(monkey(shareListHandler, "/api/shares")).Methods("GET")
|
api.Path("/shares").Handler(monkey(shareListHandler, "/api/shares")).Methods("GET")
|
||||||
api.PathPrefix("/share").Handler(monkey(shareGetsHandler, "/api/share")).Methods("GET")
|
api.PathPrefix("/share").Handler(monkey(shareGetsHandler, "/api/share")).Methods("GET")
|
||||||
|
|
|
@ -71,14 +71,20 @@ func previewHandler(imgSvc ImgService, fileCache FileCache, enableThumbnails, re
|
||||||
func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgService, fileCache FileCache,
|
func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgService, fileCache FileCache,
|
||||||
file *files.FileInfo, previewSize PreviewSize, enableThumbnails, resizePreview bool) (int, error) {
|
file *files.FileInfo, previewSize PreviewSize, enableThumbnails, resizePreview bool) (int, error) {
|
||||||
format, err := imgSvc.FormatFromExtension(file.Extension)
|
format, err := imgSvc.FormatFromExtension(file.Extension)
|
||||||
if err != nil {
|
|
||||||
// Unsupported extensions directly return the raw data
|
// Unsupported extensions directly return the raw data
|
||||||
if err == img.ErrUnsupportedFormat {
|
if err == img.ErrUnsupportedFormat || format == img.FormatGif {
|
||||||
return rawFileHandler(w, r, file)
|
return rawFileHandler(w, r, file)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isFresh := checkEtag(w, r, file.ModTime.Unix(), file.Size)
|
||||||
|
if isFresh {
|
||||||
|
return http.StatusNotModified, nil
|
||||||
|
}
|
||||||
|
|
||||||
cacheKey := previewCacheKey(file.Path, file.ModTime.Unix(), previewSize)
|
cacheKey := previewCacheKey(file.Path, file.ModTime.Unix(), previewSize)
|
||||||
cachedFile, ok, err := fileCache.Load(r.Context(), cacheKey)
|
cachedFile, ok, err := fileCache.Load(r.Context(), cacheKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -89,10 +95,22 @@ func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgServic
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err := file.Fs.Open(file.Path)
|
resizedImage, err := createPreview(imgSvc, fileCache, file, previewSize, enableThumbnails, resizePreview)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, _ = w.Write(resizedImage.Bytes())
|
||||||
|
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPreview(imgSvc ImgService, fileCache FileCache,
|
||||||
|
file *files.FileInfo, previewSize PreviewSize, enableThumbnails, resizePreview bool) (*bytes.Buffer, error) {
|
||||||
|
fd, err := file.Fs.Open(file.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -102,7 +120,7 @@ func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgServic
|
||||||
)
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case previewSize == PreviewSizeBig && resizePreview && format != img.FormatGif:
|
case previewSize == PreviewSizeBig && resizePreview:
|
||||||
width = 1080
|
width = 1080
|
||||||
height = 1080
|
height = 1080
|
||||||
options = append(options, img.WithMode(img.ResizeModeFit), img.WithQuality(img.QualityMedium))
|
options = append(options, img.WithMode(img.ResizeModeFit), img.WithQuality(img.QualityMedium))
|
||||||
|
@ -111,26 +129,22 @@ func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgServic
|
||||||
height = 128
|
height = 128
|
||||||
options = append(options, img.WithMode(img.ResizeModeFill), img.WithQuality(img.QualityLow), img.WithFormat(img.FormatJpeg))
|
options = append(options, img.WithMode(img.ResizeModeFill), img.WithQuality(img.QualityLow), img.WithFormat(img.FormatJpeg))
|
||||||
default:
|
default:
|
||||||
if _, err := rawFileHandler(w, r, file); err != nil {
|
return nil, img.ErrUnsupportedFormat
|
||||||
return errToStatus(err), err
|
|
||||||
}
|
|
||||||
return 0, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
if err := imgSvc.Resize(context.Background(), fd, width, height, buf, options...); err != nil {
|
if err := imgSvc.Resize(context.Background(), fd, width, height, buf, options...); err != nil {
|
||||||
return 0, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
cacheKey := previewCacheKey(file.Path, file.ModTime.Unix(), previewSize)
|
||||||
if err := fileCache.Store(context.Background(), cacheKey, buf.Bytes()); err != nil {
|
if err := fileCache.Store(context.Background(), cacheKey, buf.Bytes()); err != nil {
|
||||||
fmt.Printf("failed to cache resized image: %v", err)
|
fmt.Printf("failed to cache resized image: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
_, _ = w.Write(buf.Bytes())
|
return buf, nil
|
||||||
|
|
||||||
return 0, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func previewCacheKey(fPath string, fTime int64, previewSize PreviewSize) string {
|
func previewCacheKey(fPath string, fTime int64, previewSize PreviewSize) string {
|
||||||
|
|
|
@ -38,7 +38,7 @@ var withHashFile = func(fn handleFunc) handleFunc {
|
||||||
Fs: d.user.Fs,
|
Fs: d.user.Fs,
|
||||||
Path: link.Path,
|
Path: link.Path,
|
||||||
Modify: d.user.Perm.Modify,
|
Modify: d.user.Perm.Modify,
|
||||||
Expand: true,
|
Expand: false,
|
||||||
ReadHeader: d.server.TypeDetectionByHeader,
|
ReadHeader: d.server.TypeDetectionByHeader,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
Token: link.Token,
|
Token: link.Token,
|
||||||
|
|
|
@ -204,6 +204,11 @@ func rawDirHandler(w http.ResponseWriter, r *http.Request, d *data, file *files.
|
||||||
}
|
}
|
||||||
|
|
||||||
func rawFileHandler(w http.ResponseWriter, r *http.Request, file *files.FileInfo) (int, error) {
|
func rawFileHandler(w http.ResponseWriter, r *http.Request, file *files.FileInfo) (int, error) {
|
||||||
|
isFresh := checkEtag(w, r, file.ModTime.Unix(), file.Size)
|
||||||
|
if isFresh {
|
||||||
|
return http.StatusNotModified, nil
|
||||||
|
}
|
||||||
|
|
||||||
fd, err := file.Fs.Open(file.Path)
|
fd, err := file.Fs.Open(file.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
|
|
|
@ -27,6 +27,7 @@ var resourceGetHandler = withUser(func(w http.ResponseWriter, r *http.Request, d
|
||||||
Expand: true,
|
Expand: true,
|
||||||
ReadHeader: d.server.TypeDetectionByHeader,
|
ReadHeader: d.server.TypeDetectionByHeader,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
|
Content: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
|
@ -63,7 +64,7 @@ func resourceDeleteHandler(fileCache FileCache) handleFunc {
|
||||||
Fs: d.user.Fs,
|
Fs: d.user.Fs,
|
||||||
Path: r.URL.Path,
|
Path: r.URL.Path,
|
||||||
Modify: d.user.Perm.Modify,
|
Modify: d.user.Perm.Modify,
|
||||||
Expand: true,
|
Expand: false,
|
||||||
ReadHeader: d.server.TypeDetectionByHeader,
|
ReadHeader: d.server.TypeDetectionByHeader,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
})
|
})
|
||||||
|
@ -109,7 +110,7 @@ func resourcePostHandler(fileCache FileCache) handleFunc {
|
||||||
Fs: d.user.Fs,
|
Fs: d.user.Fs,
|
||||||
Path: r.URL.Path,
|
Path: r.URL.Path,
|
||||||
Modify: d.user.Perm.Modify,
|
Modify: d.user.Perm.Modify,
|
||||||
Expand: true,
|
Expand: false,
|
||||||
ReadHeader: d.server.TypeDetectionByHeader,
|
ReadHeader: d.server.TypeDetectionByHeader,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
})
|
})
|
||||||
|
@ -180,7 +181,8 @@ var resourcePutHandler = withUser(func(w http.ResponseWriter, r *http.Request, d
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
})
|
})
|
||||||
|
|
||||||
var resourcePatchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
func resourcePatchHandler(fileCache FileCache) handleFunc {
|
||||||
|
return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||||
src := r.URL.Path
|
src := r.URL.Path
|
||||||
dst := r.URL.Query().Get("destination")
|
dst := r.URL.Query().Get("destination")
|
||||||
action := r.URL.Query().Get("action")
|
action := r.URL.Query().Get("action")
|
||||||
|
@ -194,7 +196,9 @@ var resourcePatchHandler = withUser(func(w http.ResponseWriter, r *http.Request,
|
||||||
if dst == "/" || src == "/" {
|
if dst == "/" || src == "/" {
|
||||||
return http.StatusForbidden, nil
|
return http.StatusForbidden, nil
|
||||||
}
|
}
|
||||||
if err = checkParent(src, dst); err != nil {
|
|
||||||
|
err = checkParent(src, dst)
|
||||||
|
if err != nil {
|
||||||
return http.StatusBadRequest, err
|
return http.StatusBadRequest, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,29 +219,12 @@ var resourcePatchHandler = withUser(func(w http.ResponseWriter, r *http.Request,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = d.RunHook(func() error {
|
err = d.RunHook(func() error {
|
||||||
switch action {
|
return patchAction(r.Context(), action, src, dst, d, fileCache)
|
||||||
// TODO: use enum
|
|
||||||
case "copy":
|
|
||||||
if !d.user.Perm.Create {
|
|
||||||
return errors.ErrPermissionDenied
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileutils.Copy(d.user.Fs, src, dst)
|
|
||||||
case "rename":
|
|
||||||
if !d.user.Perm.Rename {
|
|
||||||
return errors.ErrPermissionDenied
|
|
||||||
}
|
|
||||||
src = path.Clean("/" + src)
|
|
||||||
dst = path.Clean("/" + dst)
|
|
||||||
|
|
||||||
return fileutils.MoveFile(d.user.Fs, src, dst)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams)
|
|
||||||
}
|
|
||||||
}, action, src, dst, d.user)
|
}, action, src, dst, d.user)
|
||||||
|
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func checkParent(src, dst string) error {
|
func checkParent(src, dst string) error {
|
||||||
rel, err := filepath.Rel(src, dst)
|
rel, err := filepath.Rel(src, dst)
|
||||||
|
@ -308,3 +295,43 @@ func delThumbs(ctx context.Context, fileCache FileCache, file *files.FileInfo) e
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func patchAction(ctx context.Context, action, src, dst string, d *data, fileCache FileCache) error {
|
||||||
|
switch action {
|
||||||
|
// TODO: use enum
|
||||||
|
case "copy":
|
||||||
|
if !d.user.Perm.Create {
|
||||||
|
return errors.ErrPermissionDenied
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileutils.Copy(d.user.Fs, src, dst)
|
||||||
|
case "rename":
|
||||||
|
if !d.user.Perm.Rename {
|
||||||
|
return errors.ErrPermissionDenied
|
||||||
|
}
|
||||||
|
src = path.Clean("/" + src)
|
||||||
|
dst = path.Clean("/" + dst)
|
||||||
|
|
||||||
|
file, err := files.NewFileInfo(files.FileOptions{
|
||||||
|
Fs: d.user.Fs,
|
||||||
|
Path: src,
|
||||||
|
Modify: d.user.Perm.Modify,
|
||||||
|
Expand: false,
|
||||||
|
ReadHeader: false,
|
||||||
|
Checker: d,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete thumbnails
|
||||||
|
err = delThumbs(ctx, fileCache, file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileutils.MoveFile(d.user.Fs, src, dst)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -71,7 +72,7 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := json.MarshalIndent(data, "", " ")
|
b, err := json.Marshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
@ -109,6 +110,9 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
|
||||||
return http.StatusNotFound, nil
|
return http.StatusNotFound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxAge = 86400 // 1 day
|
||||||
|
w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%v", maxAge))
|
||||||
|
|
||||||
if d.settings.Branding.Files != "" {
|
if d.settings.Branding.Files != "" {
|
||||||
if strings.HasPrefix(r.URL.Path, "img/") {
|
if strings.HasPrefix(r.URL.Path, "img/") {
|
||||||
fPath := filepath.Join(d.settings.Branding.Files, r.URL.Path)
|
fPath := filepath.Join(d.settings.Branding.Files, r.URL.Path)
|
||||||
|
@ -127,7 +131,19 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleWithStaticData(w, r, d, assetsFs, r.URL.Path, "application/javascript; charset=utf-8")
|
fileContents, err := fs.ReadFile(assetsFs, r.URL.Path+".gz")
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusNotFound, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Encoding", "gzip")
|
||||||
|
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
|
||||||
|
|
||||||
|
if _, err := w.Write(fileContents); err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, nil
|
||||||
}, "/static/", store, server)
|
}, "/static/", store, server)
|
||||||
|
|
||||||
return index, static
|
return index, static
|
||||||
|
|
|
@ -3,6 +3,7 @@ package http
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -66,3 +67,11 @@ func stripPrefix(prefix string, h http.Handler) http.Handler {
|
||||||
h.ServeHTTP(w, r2)
|
h.ServeHTTP(w, r2)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkEtag(w http.ResponseWriter, r *http.Request, fTime, fSize int64) bool {
|
||||||
|
etag := fmt.Sprintf("%x%x", fTime, fSize)
|
||||||
|
w.Header().Set("Cache-Control", "private")
|
||||||
|
w.Header().Set("Etag", etag)
|
||||||
|
|
||||||
|
return r.Header.Get("If-None-Match") == etag
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue