diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6d1ad9aee..ccc8d83bb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2704,11 +2704,6 @@ "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==" }, - "@types/geojson": { - "version": "7946.0.7", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz", - "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==" - }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", @@ -2719,14 +2714,6 @@ "@types/node": "*" } }, - "@types/leaflet": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.5.7.tgz", - "integrity": "sha512-FiPU4NQwH+jQ2wc3IjD7+9hgNZ95m4ry8qILO+eS6L4eUUVSXr+472+k4SRVEW+8j18QwqY7PFqudDQzfpRXTQ==", - "requires": { - "@types/geojson": "*" - } - }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -2768,9 +2755,9 @@ } }, "@types/webpack": { - "version": "4.41.2", - "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.2.tgz", - "integrity": "sha512-DNMQOfEvwzWRRyp6Wy9QVCgJ3gkelZsuBE2KUD318dg95s9DKGiT5CszmmV58hq8jk89I9NClre48AEy1MWAJA==", + "version": "4.41.3", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.3.tgz", + "integrity": "sha512-dH+BZ6pHBZFrXpnif0YU/PbmUq3lQrvRPnqkxsciSIzvG/DE+Vm/Wrjn56T7V3+B5ryQa5fw0oGnHL8tk4ll6w==", "requires": { "@types/anymatch": "*", "@types/node": "*", @@ -2788,9 +2775,9 @@ } }, "@types/webpack-sources": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.5.tgz", - "integrity": "sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.6.tgz", + "integrity": "sha512-FtAWR7wR5ocJ9+nP137DV81tveD/ZgB1sadnJ/axUGM3BUVfRPx8oQNMtv3JNfTeHx3VP7cXiyfR/jmtEsVHsQ==", "requires": { "@types/node": "*", "@types/source-list-map": "*", @@ -3228,11 +3215,11 @@ } }, "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", + "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" @@ -3484,24 +3471,19 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, "autoprefixer": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.3.tgz", - "integrity": "sha512-8T5Y1C5Iyj6PgkPSFd0ODvK9DIleuPKUPYniNxybS47g2k2wFgLZ46lGQHlBuGKIAEV8fbCDfKCCRS1tvOgc3Q==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.4.tgz", + "integrity": "sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g==", "requires": { - "browserslist": "^4.8.0", - "caniuse-lite": "^1.0.30001012", + "browserslist": "^4.8.3", + "caniuse-lite": "^1.0.30001020", "chalk": "^2.4.2", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", - "postcss": "^7.0.23", + "postcss": "^7.0.26", "postcss-value-parser": "^4.0.2" }, "dependencies": { - "caniuse-lite": { - "version": "1.0.30001012", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz", - "integrity": "sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg==" - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -3520,9 +3502,9 @@ } }, "axios": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.1.tgz", - "integrity": "sha512-Yl+7nfreYKaLRvAvjNPkvfjnQHJM1yLBY3zhqAwcJSwR/6ETkanUgylgtIvkvz0xJ+p/vZuNw8X7Hnb7Whsbpw==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", "requires": { "follow-redirects": "1.5.10" }, @@ -4145,19 +4127,19 @@ } }, "browserslist": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.3.tgz", - "integrity": "sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg==", + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", + "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", "requires": { - "caniuse-lite": "^1.0.30001017", - "electron-to-chromium": "^1.3.322", - "node-releases": "^1.1.44" + "caniuse-lite": "^1.0.30001022", + "electron-to-chromium": "^1.3.338", + "node-releases": "^1.1.46" }, "dependencies": { "caniuse-lite": { - "version": "1.0.30001019", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001019.tgz", - "integrity": "sha512-6ljkLtF1KM5fQ+5ZN0wuyVvvebJxgJPTmScOMaFuQN2QuOzvRJnWSKfzQskQU5IOU4Gap3zasYPIinzwUjoj/g==" + "version": "1.0.30001022", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz", + "integrity": "sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A==" } } }, @@ -5615,9 +5597,9 @@ } }, "earcut": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.1.tgz", - "integrity": "sha512-5jIMi2RB3HtGPHcYd9Yyl0cczo84y+48lgKPxMijliNQaKAHEZJbdzLmKmdxG/mCdS/YD9DQ1gihL8mxzR0F9w==" + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.2.tgz", + "integrity": "sha512-eZoZPPJcUHnfRZ0PjLvx2qBordSiO8ofC3vt+qACLM95u+4DovnbYNpQtJh0DNsWj8RnxrQytD4WA8gj5cRIaQ==" }, "easygettext": { "version": "2.9.0", @@ -5654,9 +5636,9 @@ "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" }, "electron-to-chromium": { - "version": "1.3.333", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.333.tgz", - "integrity": "sha512-7MJfCpa/tmhqYy2lZ1NEbkSxH7q3KiZiepiSs2ayTPAweAjdzGXotij+7OKPPb3OwJD2ZuBKPrA2HIuuSi6ahw==" + "version": "1.3.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz", + "integrity": "sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==" }, "elliptic": { "version": "6.5.2", @@ -5786,9 +5768,9 @@ } }, "es-abstract": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", - "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -6303,9 +6285,9 @@ "integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==" }, "eslint-rule-docs": { - "version": "1.1.174", - "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.174.tgz", - "integrity": "sha512-YgxPdamf/Wmpg5+JiU24KOLgDnPWf54Z+S4fbY9IqssNCTTxFeeVV18YI42hM6hZvhMo8fsXYaTPC9qzJEwpYw==" + "version": "1.1.175", + "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.175.tgz", + "integrity": "sha512-jFBHgUeNAguil2gHyHJTTH8vBJ4W+abJz/Lm9z93Gv5FsZ//r8aGaaGSuFZDzLNB411EGBjwmTdt6rwAi0J7JQ==" }, "eslint-scope": { "version": "5.0.0", @@ -6634,9 +6616,9 @@ } }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" }, "fast-json-stable-stringify": { "version": "2.1.0", @@ -6933,9 +6915,9 @@ } }, "fs-minipass": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.0.0.tgz", - "integrity": "sha512-40Qz+LFXmd9tzYVnnBmZvFfvAADfUA14TXPK1s7IfElJTIZ97rA8w4Kin7Wt5JBrC3ShnnFJO/5vPjPEeJIq9A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "requires": { "minipass": "^3.0.0" } @@ -8891,9 +8873,9 @@ "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==" }, "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, "last-call-webpack-plugin": { "version": "3.0.0", @@ -9768,9 +9750,9 @@ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" }, "node-releases": { - "version": "1.1.45", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.45.tgz", - "integrity": "sha512-cXvGSfhITKI8qsV116u2FTzH5EWZJfgG7d4cpqwF8I8+1tWpD6AsvvGRKq2onR0DNj1jfqsjkXZsm14JMS7Cyg==", + "version": "1.1.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", + "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", "requires": { "semver": "^6.3.0" }, @@ -12064,9 +12046,9 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "resolve": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.2.tgz", - "integrity": "sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", "requires": { "path-parse": "^1.0.6" } @@ -13757,9 +13739,9 @@ "integrity": "sha512-M8wx+OV7uCGOQ/iLi5d2WHbWW9ad9uBPsW50iezV7LDrZ6iuXkDJSCmTaQgnRKJWOOfPsQrgNFME1LKMRrFmgg==" }, "vue-gettext": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/vue-gettext/-/vue-gettext-2.1.7.tgz", - "integrity": "sha512-cRYhrMq1iNRWOBYaXJtgBQPzNm2TgtK91nJdP+8EnO7q1ecMB0E66e719kMfJAcUXVmQRXm+smOUpX8CM5SWEw==" + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/vue-gettext/-/vue-gettext-2.1.8.tgz", + "integrity": "sha512-LzDnD12g/DOqvDcQbwQTeeyS1E8WGs9L2tJoXzISWDinibUsm3fsEaQCo0mTZ0NpDHsk2AK2KzyuWly0Yulp9Q==" }, "vue-hot-reload-api": { "version": "2.3.3", @@ -13880,9 +13862,9 @@ } }, "vue-router": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.4.tgz", - "integrity": "sha512-pX2BGvZg5/MOXbJoYsRppoZM+0B4LSszvIXQvLPZ7govbgbBorYQ4JHx99lDTjzEBkbTyKfRG+ru1VCnMuVcUg==" + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.5.tgz", + "integrity": "sha512-BszkPvhl7I9h334GjckCh7sVFyjTPMMJFJ4Bsrem/Ik+B/9gt5tgrk8k4gGLO4ZpdvciVdg7O41gW4DisQWurg==" }, "vue-style-loader": { "version": "4.1.2", diff --git a/frontend/package.json b/frontend/package.json index 3b568da40..e92bf433b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,16 +25,15 @@ "@babel/register": "^7.8.3", "@babel/runtime": "^7.8.3", "@fortawesome/fontawesome-free": "^5.12.0", - "@types/leaflet": "^1.5.7", "acorn": "^6.4.0", - "ajv": "^6.10.2", - "autoprefixer": "^9.7.3", - "axios": "^0.19.1", + "ajv": "^6.11.0", + "autoprefixer": "^9.7.4", + "axios": "^0.19.2", "axios-mock-adapter": "^1.17.0", "babel-eslint": "^10.0.3", "babel-loader": "^8.0.6", "babel-plugin-istanbul": "^6.0.0", - "browserslist": "^4.8.3", + "browserslist": "^4.8.5", "chai": "^4.2.0", "chalk": "^3.0.0", "chart.js": "^2.9.3", @@ -104,11 +103,11 @@ "url-loader": "^1.1.2", "vue": "^2.6.11", "vue-fullscreen": "^2.1.5", - "vue-gettext": "^2.1.7", + "vue-gettext": "^2.1.8", "vue-infinite-scroll": "^2.0.2", "vue-loader": "^14.2.4", "vue-luxon": "^0.7.0", - "vue-router": "^3.1.4", + "vue-router": "^3.1.5", "vue-style-loader": "^4.1.2", "vue-template-compiler": "^2.6.11", "vue2-filters": "^0.9.1", diff --git a/frontend/src/app.js b/frontend/src/app.js index c6d76d6d6..4845e02e0 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -2,7 +2,6 @@ import "core-js/stable"; import "regenerator-runtime/runtime"; import Api from "common/api"; import Notify from "common/notify"; -import Config from "common/config"; import Clipboard from "common/clipboard"; import Components from "component/components"; import Dialogs from "dialog/dialogs"; @@ -12,7 +11,7 @@ import Log from "common/log"; import PhotoPrism from "photoprism.vue"; import Router from "vue-router"; import Routes from "routes"; -import Session from "session"; +import {session, config} from "session"; import {Settings} from "luxon"; import Socket from "common/websocket"; import Viewer from "common/viewer"; @@ -24,7 +23,6 @@ import VueFullscreen from "vue-fullscreen"; import VueInfiniteScroll from "vue-infinite-scroll"; // Initialize helpers -const config = new Config(window.localStorage, window.clientConfig); const viewer = new Viewer(); const clipboard = new Clipboard(window.localStorage, "photo_clipboard"); const isPublic = config.getValue("public"); @@ -33,7 +31,7 @@ const isPublic = config.getValue("public"); Vue.prototype.$event = Event; Vue.prototype.$notify = Notify; Vue.prototype.$viewer = viewer; -Vue.prototype.$session = Session; +Vue.prototype.$session = session; Vue.prototype.$api = Api; Vue.prototype.$log = Log; Vue.prototype.$socket = Socket; @@ -70,7 +68,7 @@ const router = new Router({ router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.admin)) { - if (isPublic || Session.isAdmin()) { + if (isPublic || session.isAdmin()) { next(); } else { next({ @@ -79,7 +77,7 @@ router.beforeEach((to, from, next) => { }); } } else if (to.matched.some(record => record.meta.auth)) { - if (isPublic || Session.isUser()) { + if (isPublic || session.isUser()) { next(); } else { next({ diff --git a/frontend/src/common/session.js b/frontend/src/common/session.js index 869d1f325..99627f136 100644 --- a/frontend/src/common/session.js +++ b/frontend/src/common/session.js @@ -6,9 +6,11 @@ import Socket from "./websocket"; export default class Session { /** * @param {Storage} storage + * @param {Config} config */ - constructor(storage) { + constructor(storage, config) { this.auth = false; + this.config = config; if (storage.getItem("session_storage") === "true") { this.storage = window.sessionStorage; @@ -26,14 +28,14 @@ export default class Session { } Event.subscribe("session.logout", () => { - this.onLogout() + this.onLogout(); }); Event.subscribe("websocket.connected", () => { - this.sendClientInfo() + this.sendClientInfo(); }); - this.sendClientInfo() + this.sendClientInfo(); } useSessionStorage() { @@ -64,6 +66,10 @@ export default class Session { return this.applyToken(token); } + setConfig(values) { + this.config.setValues(values); + } + getToken() { return this.session_token; } @@ -138,7 +144,7 @@ export default class Session { try { Socket.send(JSON.stringify(clientInfo)); } catch(e) { - console.log("can't send client info, websocket not connected (yet)") + console.log("can't send client info, websocket not connected (yet)"); } } @@ -147,6 +153,7 @@ export default class Session { return Api.post("session", {email: email, password: password}).then( (result) => { + this.setConfig(result.data.config); this.setToken(result.data.token); this.setUser(new User(result.data.user)); this.sendClientInfo(); diff --git a/frontend/src/routes.js b/frontend/src/routes.js index 9ad2aae4b..1fd848263 100644 --- a/frontend/src/routes.js +++ b/frontend/src/routes.js @@ -132,7 +132,7 @@ export default [ name: "settings", path: "/settings", component: Settings, - meta: {title: "Application Settings", auth: true, background: "application-light"}, + meta: {title: "Settings", auth: true, background: "application-light"}, props: {tab: 0}, }, { diff --git a/frontend/src/session.js b/frontend/src/session.js index 3d46ab40b..ba673a146 100644 --- a/frontend/src/session.js +++ b/frontend/src/session.js @@ -1,5 +1,7 @@ +import Config from "common/config"; import Session from "common/session"; -const session = new Session(window.localStorage); +export const config = new Config(window.localStorage, window.clientConfig); +export const session = new Session(window.localStorage, config); export default session; diff --git a/frontend/tests/unit/common/session_test.js b/frontend/tests/unit/common/session_test.js index baa1d01e5..e46bf8b1e 100644 --- a/frontend/tests/unit/common/session_test.js +++ b/frontend/tests/unit/common/session_test.js @@ -1,12 +1,14 @@ import Session from 'common/session'; +import Config from 'common/config' import User from 'model/user'; import MockAdapter from "axios-mock-adapter"; import Api from "common/api"; +window.clientConfig = {"albums":[{"ID":1,"CoverUUID":"","AlbumUUID":"aq4gs3w2x9r0m7ppx","AlbumSlug":"cat-power","AlbumName":"Cat Power","AlbumDescription":"","AlbumNotes":"","AlbumViews":0,"AlbumFavorite":true,"AlbumPublic":false,"AlbumLat":0,"AlbumLng":0,"AlbumRadius":0,"AlbumOrder":"","AlbumTemplate":"","CreatedAt":"2020-01-21T15:52:45Z","UpdatedAt":"2020-01-21T15:52:45Z","DeletedAt":null}],"author":"PhotoPrism.org","cameras":[{"ID":60009,"CameraSlug":"neingrenze-5000t","CameraModel":"5000T","CameraMake":"NEINGRENZE","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:26:05Z","UpdatedAt":"2020-01-15T17:26:05Z","DeletedAt":null},{"ID":60007,"CameraSlug":"olympus-optical-co-ltd-c2500l","CameraModel":"C2500L ","CameraMake":"OLYMPUS OPTICAL CO.,LTD","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:33Z","UpdatedAt":"2020-01-15T17:27:51Z","DeletedAt":null},{"ID":60004,"CameraSlug":"canon-eos-10d","CameraModel":"EOS 10D","CameraMake":"Canon","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:10Z","UpdatedAt":"2020-01-15T17:27:42Z","DeletedAt":null},{"ID":60006,"CameraSlug":"canon-eos-5d","CameraModel":"EOS 5D","CameraMake":"Canon","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:31Z","UpdatedAt":"2020-01-22T09:33:39Z","DeletedAt":null},{"ID":60002,"CameraSlug":"canon-eos-6d","CameraModel":"EOS 6D","CameraMake":"Canon","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:04Z","UpdatedAt":"2020-01-20T10:36:41Z","DeletedAt":null},{"ID":60005,"CameraSlug":"canon-eos-7d","CameraModel":"EOS 7D","CameraMake":"Canon","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:27Z","UpdatedAt":"2020-01-15T17:27:55Z","DeletedAt":null},{"ID":30001,"CameraSlug":"unknown","CameraModel":"Unknown","CameraMake":"","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T03:59:45Z","UpdatedAt":"2020-01-16T22:45:46Z","DeletedAt":null},{"ID":60008,"CameraSlug":"apple-iphone-4s","CameraModel":"iPhone 4S","CameraMake":"Apple","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:34Z","UpdatedAt":"2020-01-15T17:25:34Z","DeletedAt":null},{"ID":60001,"CameraSlug":"apple-iphone-5s","CameraModel":"iPhone 5s","CameraMake":"Apple","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:03Z","UpdatedAt":"2020-01-15T17:27:53Z","DeletedAt":null},{"ID":60003,"CameraSlug":"apple-iphone-6","CameraModel":"iPhone 6","CameraMake":"Apple","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:10Z","UpdatedAt":"2020-01-16T22:45:43Z","DeletedAt":null},{"ID":1,"CameraSlug":"apple-iphone-se","CameraModel":"iPhone SE","CameraMake":"Apple","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-14T01:16:46Z","UpdatedAt":"2020-01-15T17:27:15Z","DeletedAt":null}],"categories":[{"LabelName":"airport","Title":"Airport"},{"LabelName":"animal","Title":"Animal"},{"LabelName":"architecture","Title":"Architecture"},{"LabelName":"beach","Title":"Beach"},{"LabelName":"beetle","Title":"Beetle"},{"LabelName":"beverage","Title":"Beverage"},{"LabelName":"bird","Title":"Bird"},{"LabelName":"bridge","Title":"Bridge"},{"LabelName":"building","Title":"Building"},{"LabelName":"car","Title":"Car"},{"LabelName":"cat","Title":"Cat"},{"LabelName":"computer","Title":"Computer"},{"LabelName":"drinks","Title":"Drinks"},{"LabelName":"farm","Title":"Farm"},{"LabelName":"flower","Title":"Flower"},{"LabelName":"fruit","Title":"Fruit"},{"LabelName":"info","Title":"Info"},{"LabelName":"kitchen","Title":"Kitchen"},{"LabelName":"landscape","Title":"Landscape"},{"LabelName":"lizard","Title":"Lizard"},{"LabelName":"monkey","Title":"Monkey"},{"LabelName":"nature","Title":"Nature"},{"LabelName":"office","Title":"Office"},{"LabelName":"outdoor","Title":"Outdoor"},{"LabelName":"people","Title":"People"},{"LabelName":"plant","Title":"Plant"},{"LabelName":"portrait","Title":"Portrait"},{"LabelName":"reptile","Title":"Reptile"},{"LabelName":"rodent","Title":"Rodent"},{"LabelName":"sand","Title":"Sand"},{"LabelName":"shop","Title":"Shop"},{"LabelName":"table","Title":"Table"},{"LabelName":"tower","Title":"Tower"},{"LabelName":"train","Title":"Train"},{"LabelName":"vegetables","Title":"Vegetables"},{"LabelName":"vehicle","Title":"Vehicle"},{"LabelName":"water","Title":"Water"},{"LabelName":"wildlife","Title":"Wildlife"}],"colors":[{"example":"#AB47BC","label":"Purple","name":"purple"},{"example":"#FF00FF","label":"Magenta","name":"magenta"},{"example":"#EC407A","label":"Pink","name":"pink"},{"example":"#EF5350","label":"Red","name":"red"},{"example":"#FFA726","label":"Orange","name":"orange"},{"example":"#D4AF37","label":"Gold","name":"gold"},{"example":"#FDD835","label":"Yellow","name":"yellow"},{"example":"#CDDC39","label":"Lime","name":"lime"},{"example":"#66BB6A","label":"Green","name":"green"},{"example":"#009688","label":"Teal","name":"teal"},{"example":"#00BCD4","label":"Cyan","name":"cyan"},{"example":"#2196F3","label":"Blue","name":"blue"},{"example":"#A1887F","label":"Brown","name":"brown"},{"example":"#F5F5F5","label":"White","name":"white"},{"example":"#9E9E9E","label":"Grey","name":"grey"},{"example":"#212121","label":"Black","name":"black"}],"copyright":"(c) 2018-2020 The PhotoPrism contributors \u003chello@photoprism.org\u003e","count":{"photos":712,"favorites":9,"private":2,"stories":2,"labels":86,"albums":1,"countries":8,"places":44},"countries":[{"code":"bw","name":"Botswana"},{"code":"cu","name":"Cuba"},{"code":"fr","name":"France"},{"code":"de","name":"Germany"},{"code":"gr","name":"Greece"},{"code":"za","name":"South Africa"},{"code":"ch","name":"Switzerland"},{"code":"us","name":"USA"},{"code":"zz","name":"Unknown"}],"cssHash":"9104a800d818ae72175b68dfcbc44c3536351746","debug":true,"description":"Personal Photo Management","experimental":true,"flags":"public debug experimental","jsHash":"12f304d05e6ef4f50f6f5394e5a95fc697426204","lenses":[{"ID":60007,"LensSlug":"28-0-75-0-mm","LensModel":"28.0-75.0 mm","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:26:02Z","UpdatedAt":"2020-01-15T17:26:02Z","DeletedAt":null},{"ID":60005,"LensSlug":"ef100mm-f-2-8l-macro-is-usm","LensModel":"EF100mm f/2.8L Macro IS USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:29Z","UpdatedAt":"2020-01-15T17:27:46Z","DeletedAt":null},{"ID":60004,"LensSlug":"ef16-35mm-f-2-8l-ii-usm","LensModel":"EF16-35mm f/2.8L II USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:28Z","UpdatedAt":"2020-01-15T17:26:41Z","DeletedAt":null},{"ID":60002,"LensSlug":"ef24-105mm-f-4l-is-usm","LensModel":"EF24-105mm f/4L IS USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:04Z","UpdatedAt":"2020-01-16T22:22:51Z","DeletedAt":null},{"ID":60008,"LensSlug":"ef35mm-f-2-is-usm","LensModel":"EF35mm f/2 IS USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:26:16Z","UpdatedAt":"2020-01-20T10:36:41Z","DeletedAt":null},{"ID":60006,"LensSlug":"ef70-200mm-f-4l-is-usm","LensModel":"EF70-200mm f/4L IS USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:53Z","UpdatedAt":"2020-01-16T22:22:57Z","DeletedAt":null},{"ID":30001,"LensSlug":"unknown","LensModel":"Unknown","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T03:59:45Z","UpdatedAt":"2020-01-22T09:33:39Z","DeletedAt":null},{"ID":60001,"LensSlug":"iphone-5s-back-camera-4-12mm-f-2-2","LensModel":"iPhone 5s back camera 4.12mm f/2.2","LensMake":"Apple","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:03Z","UpdatedAt":"2020-01-15T17:27:53Z","DeletedAt":null},{"ID":60003,"LensSlug":"iphone-6-back-camera-4-15mm-f-2-2","LensModel":"iPhone 6 back camera 4.15mm f/2.2","LensMake":"Apple","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:10Z","UpdatedAt":"2020-01-16T22:45:43Z","DeletedAt":null},{"ID":90001,"LensSlug":"iphone-6-front-camera-2-65mm-f-2-2","LensModel":"iPhone 6 front camera 2.65mm f/2.2","LensMake":"Apple","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-16T22:22:53Z","UpdatedAt":"2020-01-16T22:44:43Z","DeletedAt":null},{"ID":1,"LensSlug":"iphone-se-back-camera-4-15mm-f-2-2","LensModel":"iPhone SE back camera 4.15mm f/2.2","LensMake":"Apple","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-14T01:16:46Z","UpdatedAt":"2020-01-15T17:27:15Z","DeletedAt":null}],"name":"PhotoPrism","pos":{"photo":"pq45sez3bayygvd6o","location":"479a03fda574","utc":"2019-05-31T18:15:08Z","lat":48.29912222222222,"lng":8.929649999999999},"public":true,"readonly":false,"settings":{"theme":"default","language":"en"},"subtitle":"Browse your life","thumbnails":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200}],"title":"PhotoPrism","twitter":"@browseyourlife","uploadNSFW":false,"url":"http://localhost:2342/","version":"200122-f569c3a-Linux-x86_64-DEBUG","years":[2020,2019,2018,2017,2016,2015,2014,2013,2012,2011,2010,2004,2002]}; + let chai = require('../../../node_modules/chai/chai'); let assert = chai.assert; - -window.clientConfig = {"albums":[{"ID":1,"CoverUUID":"","AlbumUUID":"aq4gs3w2x9r0m7ppx","AlbumSlug":"cat-power","AlbumName":"Cat Power","AlbumDescription":"","AlbumNotes":"","AlbumViews":0,"AlbumFavorite":true,"AlbumPublic":false,"AlbumLat":0,"AlbumLng":0,"AlbumRadius":0,"AlbumOrder":"","AlbumTemplate":"","CreatedAt":"2020-01-21T15:52:45Z","UpdatedAt":"2020-01-21T15:52:45Z","DeletedAt":null}],"author":"PhotoPrism.org","cameras":[{"ID":60009,"CameraSlug":"neingrenze-5000t","CameraModel":"5000T","CameraMake":"NEINGRENZE","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:26:05Z","UpdatedAt":"2020-01-15T17:26:05Z","DeletedAt":null},{"ID":60007,"CameraSlug":"olympus-optical-co-ltd-c2500l","CameraModel":"C2500L ","CameraMake":"OLYMPUS OPTICAL CO.,LTD","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:33Z","UpdatedAt":"2020-01-15T17:27:51Z","DeletedAt":null},{"ID":60004,"CameraSlug":"canon-eos-10d","CameraModel":"EOS 10D","CameraMake":"Canon","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:10Z","UpdatedAt":"2020-01-15T17:27:42Z","DeletedAt":null},{"ID":60006,"CameraSlug":"canon-eos-5d","CameraModel":"EOS 5D","CameraMake":"Canon","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:31Z","UpdatedAt":"2020-01-22T09:33:39Z","DeletedAt":null},{"ID":60002,"CameraSlug":"canon-eos-6d","CameraModel":"EOS 6D","CameraMake":"Canon","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:04Z","UpdatedAt":"2020-01-20T10:36:41Z","DeletedAt":null},{"ID":60005,"CameraSlug":"canon-eos-7d","CameraModel":"EOS 7D","CameraMake":"Canon","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:27Z","UpdatedAt":"2020-01-15T17:27:55Z","DeletedAt":null},{"ID":30001,"CameraSlug":"unknown","CameraModel":"Unknown","CameraMake":"","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T03:59:45Z","UpdatedAt":"2020-01-16T22:45:46Z","DeletedAt":null},{"ID":60008,"CameraSlug":"apple-iphone-4s","CameraModel":"iPhone 4S","CameraMake":"Apple","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:34Z","UpdatedAt":"2020-01-15T17:25:34Z","DeletedAt":null},{"ID":60001,"CameraSlug":"apple-iphone-5s","CameraModel":"iPhone 5s","CameraMake":"Apple","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:03Z","UpdatedAt":"2020-01-15T17:27:53Z","DeletedAt":null},{"ID":60003,"CameraSlug":"apple-iphone-6","CameraModel":"iPhone 6","CameraMake":"Apple","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-15T17:25:10Z","UpdatedAt":"2020-01-16T22:45:43Z","DeletedAt":null},{"ID":1,"CameraSlug":"apple-iphone-se","CameraModel":"iPhone SE","CameraMake":"Apple","CameraType":"","CameraOwner":"","CameraDescription":"","CameraNotes":"","CreatedAt":"2020-01-14T01:16:46Z","UpdatedAt":"2020-01-15T17:27:15Z","DeletedAt":null}],"categories":[{"LabelName":"airport","Title":"Airport"},{"LabelName":"animal","Title":"Animal"},{"LabelName":"architecture","Title":"Architecture"},{"LabelName":"beach","Title":"Beach"},{"LabelName":"beetle","Title":"Beetle"},{"LabelName":"beverage","Title":"Beverage"},{"LabelName":"bird","Title":"Bird"},{"LabelName":"bridge","Title":"Bridge"},{"LabelName":"building","Title":"Building"},{"LabelName":"car","Title":"Car"},{"LabelName":"cat","Title":"Cat"},{"LabelName":"computer","Title":"Computer"},{"LabelName":"drinks","Title":"Drinks"},{"LabelName":"farm","Title":"Farm"},{"LabelName":"flower","Title":"Flower"},{"LabelName":"fruit","Title":"Fruit"},{"LabelName":"info","Title":"Info"},{"LabelName":"kitchen","Title":"Kitchen"},{"LabelName":"landscape","Title":"Landscape"},{"LabelName":"lizard","Title":"Lizard"},{"LabelName":"monkey","Title":"Monkey"},{"LabelName":"nature","Title":"Nature"},{"LabelName":"office","Title":"Office"},{"LabelName":"outdoor","Title":"Outdoor"},{"LabelName":"people","Title":"People"},{"LabelName":"plant","Title":"Plant"},{"LabelName":"portrait","Title":"Portrait"},{"LabelName":"reptile","Title":"Reptile"},{"LabelName":"rodent","Title":"Rodent"},{"LabelName":"sand","Title":"Sand"},{"LabelName":"shop","Title":"Shop"},{"LabelName":"table","Title":"Table"},{"LabelName":"tower","Title":"Tower"},{"LabelName":"train","Title":"Train"},{"LabelName":"vegetables","Title":"Vegetables"},{"LabelName":"vehicle","Title":"Vehicle"},{"LabelName":"water","Title":"Water"},{"LabelName":"wildlife","Title":"Wildlife"}],"colors":[{"example":"#AB47BC","label":"Purple","name":"purple"},{"example":"#FF00FF","label":"Magenta","name":"magenta"},{"example":"#EC407A","label":"Pink","name":"pink"},{"example":"#EF5350","label":"Red","name":"red"},{"example":"#FFA726","label":"Orange","name":"orange"},{"example":"#D4AF37","label":"Gold","name":"gold"},{"example":"#FDD835","label":"Yellow","name":"yellow"},{"example":"#CDDC39","label":"Lime","name":"lime"},{"example":"#66BB6A","label":"Green","name":"green"},{"example":"#009688","label":"Teal","name":"teal"},{"example":"#00BCD4","label":"Cyan","name":"cyan"},{"example":"#2196F3","label":"Blue","name":"blue"},{"example":"#A1887F","label":"Brown","name":"brown"},{"example":"#F5F5F5","label":"White","name":"white"},{"example":"#9E9E9E","label":"Grey","name":"grey"},{"example":"#212121","label":"Black","name":"black"}],"copyright":"(c) 2018-2020 The PhotoPrism contributors \u003chello@photoprism.org\u003e","count":{"photos":712,"favorites":9,"private":2,"stories":2,"labels":86,"albums":1,"countries":8,"places":44},"countries":[{"code":"bw","name":"Botswana"},{"code":"cu","name":"Cuba"},{"code":"fr","name":"France"},{"code":"de","name":"Germany"},{"code":"gr","name":"Greece"},{"code":"za","name":"South Africa"},{"code":"ch","name":"Switzerland"},{"code":"us","name":"USA"},{"code":"zz","name":"Unknown"}],"cssHash":"9104a800d818ae72175b68dfcbc44c3536351746","debug":true,"description":"Personal Photo Management","experimental":true,"flags":"public debug experimental","jsHash":"12f304d05e6ef4f50f6f5394e5a95fc697426204","lenses":[{"ID":60007,"LensSlug":"28-0-75-0-mm","LensModel":"28.0-75.0 mm","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:26:02Z","UpdatedAt":"2020-01-15T17:26:02Z","DeletedAt":null},{"ID":60005,"LensSlug":"ef100mm-f-2-8l-macro-is-usm","LensModel":"EF100mm f/2.8L Macro IS USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:29Z","UpdatedAt":"2020-01-15T17:27:46Z","DeletedAt":null},{"ID":60004,"LensSlug":"ef16-35mm-f-2-8l-ii-usm","LensModel":"EF16-35mm f/2.8L II USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:28Z","UpdatedAt":"2020-01-15T17:26:41Z","DeletedAt":null},{"ID":60002,"LensSlug":"ef24-105mm-f-4l-is-usm","LensModel":"EF24-105mm f/4L IS USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:04Z","UpdatedAt":"2020-01-16T22:22:51Z","DeletedAt":null},{"ID":60008,"LensSlug":"ef35mm-f-2-is-usm","LensModel":"EF35mm f/2 IS USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:26:16Z","UpdatedAt":"2020-01-20T10:36:41Z","DeletedAt":null},{"ID":60006,"LensSlug":"ef70-200mm-f-4l-is-usm","LensModel":"EF70-200mm f/4L IS USM","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:53Z","UpdatedAt":"2020-01-16T22:22:57Z","DeletedAt":null},{"ID":30001,"LensSlug":"unknown","LensModel":"Unknown","LensMake":"","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T03:59:45Z","UpdatedAt":"2020-01-22T09:33:39Z","DeletedAt":null},{"ID":60001,"LensSlug":"iphone-5s-back-camera-4-12mm-f-2-2","LensModel":"iPhone 5s back camera 4.12mm f/2.2","LensMake":"Apple","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:03Z","UpdatedAt":"2020-01-15T17:27:53Z","DeletedAt":null},{"ID":60003,"LensSlug":"iphone-6-back-camera-4-15mm-f-2-2","LensModel":"iPhone 6 back camera 4.15mm f/2.2","LensMake":"Apple","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-15T17:25:10Z","UpdatedAt":"2020-01-16T22:45:43Z","DeletedAt":null},{"ID":90001,"LensSlug":"iphone-6-front-camera-2-65mm-f-2-2","LensModel":"iPhone 6 front camera 2.65mm f/2.2","LensMake":"Apple","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-16T22:22:53Z","UpdatedAt":"2020-01-16T22:44:43Z","DeletedAt":null},{"ID":1,"LensSlug":"iphone-se-back-camera-4-15mm-f-2-2","LensModel":"iPhone SE back camera 4.15mm f/2.2","LensMake":"Apple","LensType":"","LensOwner":"","LensDescription":"","LensNotes":"","CreatedAt":"2020-01-14T01:16:46Z","UpdatedAt":"2020-01-15T17:27:15Z","DeletedAt":null}],"name":"PhotoPrism","pos":{"photo":"pq45sez3bayygvd6o","location":"479a03fda574","utc":"2019-05-31T18:15:08Z","lat":48.29912222222222,"lng":8.929649999999999},"public":true,"readonly":false,"settings":{"theme":"default","language":"en"},"subtitle":"Browse your life","thumbnails":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200}],"title":"PhotoPrism","twitter":"@browseyourlife","uploadNSFW":false,"url":"http://localhost:2342/","version":"200122-f569c3a-Linux-x86_64-DEBUG","years":[2020,2019,2018,2017,2016,2015,2014,2013,2012,2011,2010,2004,2002]}; +const config = new Config(window.localStorage, window.clientConfig); describe('common/session', () => { @@ -18,13 +20,13 @@ describe('common/session', () => { it('should construct session', () => { const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); assert.equal(session.session_token, null); }); it('should set, get and delete token', () => { const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); assert.equal(session.session_token, null); session.setToken(123421); assert.equal(session.session_token, 123421); @@ -36,7 +38,7 @@ describe('common/session', () => { it('should set, get and delete user', () => { const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); assert.equal(session.user, null); const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"}; const user = new User(values); @@ -52,7 +54,7 @@ describe('common/session', () => { it('should get user email', () => { const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"}; const user = new User(values); session.setUser(user); @@ -68,7 +70,7 @@ describe('common/session', () => { it('should get user firstname', () => { const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"}; const user = new User(values); session.setUser(user); @@ -84,7 +86,7 @@ describe('common/session', () => { it('should get user full name', () => { const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"}; const user = new User(values); session.setUser(user); @@ -100,7 +102,7 @@ describe('common/session', () => { it('should test whether user is set', () => { const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"}; const user = new User(values); session.setUser(user); @@ -111,7 +113,7 @@ describe('common/session', () => { it('should test whether user is admin', () => { const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"}; const user = new User(values); session.setUser(user); @@ -122,7 +124,7 @@ describe('common/session', () => { it('should test whether user is anonymous', () => { const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"}; const user = new User(values); session.setUser(user); @@ -136,7 +138,7 @@ describe('common/session', () => { .onPost("session").reply(200, {token: "8877", user: {ID: 1, Email: "test@test.com"}}) .onDelete("session/8877").reply(200); const storage = window.localStorage; - const session = new Session(storage); + const session = new Session(storage, config); assert.equal(session.session_token, null); assert.equal(session.storage.user, undefined); await session.login("test@test.com", "passwd"); diff --git a/internal/api/session.go b/internal/api/session.go index b789b3957..f1efb0327 100644 --- a/internal/api/session.go +++ b/internal/api/session.go @@ -5,7 +5,6 @@ import ( "github.com/gin-gonic/gin" "github.com/photoprism/photoprism/internal/config" - "github.com/photoprism/photoprism/internal/event" "github.com/photoprism/photoprism/internal/form" "github.com/photoprism/photoprism/internal/session" "github.com/photoprism/photoprism/pkg/txt" @@ -32,9 +31,7 @@ func CreateSession(router *gin.RouterGroup, conf *config.Config) { c.Header("X-Session-Token", token) - s := gin.H{"token": token, "user": user} - - event.Publish("config.updated", event.Data(conf.ClientConfig())) + s := gin.H{"token": token, "user": user, "config": conf.ClientConfig()} c.JSON(http.StatusOK, s) }) diff --git a/internal/api/websocket.go b/internal/api/websocket.go index fd805d2fe..f77e47c99 100644 --- a/internal/api/websocket.go +++ b/internal/api/websocket.go @@ -19,7 +19,7 @@ var wsConnection = websocket.Upgrader{ return true }, } -var wsTimeout = 60 * time.Second +var wsTimeout = 90 * time.Second type clientInfo struct { SessionToken string `json:"session"` @@ -33,7 +33,7 @@ var wsAuth = struct { mutex sync.RWMutex }{authenticated: make(map[string]bool)} -func wsReader(ws *websocket.Conn, connId string) { +func wsReader(ws *websocket.Conn, connId string, conf *config.Config) { defer ws.Close() ws.SetReadLimit(512) @@ -54,19 +54,25 @@ func wsReader(ws *websocket.Conn, connId string) { if err := json.Unmarshal(m, &info); err != nil { log.Error(err) } else { - log.Debugf("websocket: %+v", info) - if session.Exists(info.SessionToken) { + log.Debug("websocket: authenticated") + wsAuth.mutex.Lock() wsAuth.authenticated[connId] = true wsAuth.mutex.Unlock() + + ws.SetWriteDeadline(time.Now().Add(30 * time.Second)) + + if err := ws.WriteJSON(gin.H{"event": "config.updated", "data": event.Data(conf.ClientConfig())}); err != nil { + log.Error(err) + } } } } } func wsWriter(ws *websocket.Conn, connId string) { - pingTicker := time.NewTicker(10 * time.Second) + pingTicker := time.NewTicker(15 * time.Second) s := event.Subscribe("log.*", "notify.*", "index.*", "upload.*", "import.*", "config.*", "count.*") defer func() { @@ -82,7 +88,7 @@ func wsWriter(ws *websocket.Conn, connId string) { for { select { case <-pingTicker.C: - ws.SetWriteDeadline(time.Now().Add(10 * time.Second)) + ws.SetWriteDeadline(time.Now().Add(30 * time.Second)) if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil { return } @@ -92,7 +98,7 @@ func wsWriter(ws *websocket.Conn, connId string) { wsAuth.mutex.RUnlock() if auth { - ws.SetWriteDeadline(time.Now().Add(10 * time.Second)) + ws.SetWriteDeadline(time.Now().Add(30 * time.Second)) if err := ws.WriteJSON(gin.H{"event": msg.Name, "data": msg.Fields}); err != nil { log.Debug(err) @@ -139,6 +145,6 @@ func Websocket(router *gin.RouterGroup, conf *config.Config) { go wsWriter(ws, connId) - wsReader(ws, connId) + wsReader(ws, connId, conf) }) } diff --git a/internal/server/routes.go b/internal/server/routes.go index 35fd7a218..ca5ba3593 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -72,7 +72,6 @@ func registerRoutes(router *gin.Engine, conf *config.Config) { // Default HTML page (client-side routing implemented via Vue.js) router.NoRoute(func(c *gin.Context) { - // Todo: Use PublicClientConfig() - c.HTML(http.StatusOK, "index.tmpl", gin.H{"clientConfig": conf.ClientConfig()}) + c.HTML(http.StatusOK, "index.tmpl", gin.H{"clientConfig": conf.PublicClientConfig()}) }) }