From d656990de493fe77aa94038bc3736506c1b18bb6 Mon Sep 17 00:00:00 2001 From: Matthias Nagel Date: Mon, 5 Sep 2022 11:31:05 +0200 Subject: [PATCH] Add user and better structure to session json (#310) * Adopted backend definition * Adopted main module * Adopted album * Adopted context menu * Adopted header * Adopted multi select * Adopted view * Update user object after update --- scripts/3rd-party/backend.js | 7 +--- scripts/main/album.js | 6 +-- scripts/main/contextMenu.js | 14 ++++--- scripts/main/header.js | 2 +- scripts/main/lychee.js | 76 +++++++++++++++++------------------- scripts/main/multiselect.js | 2 +- scripts/main/settings.js | 25 +++++++++--- scripts/main/view.js | 6 +-- 8 files changed, 73 insertions(+), 65 deletions(-) diff --git a/scripts/3rd-party/backend.js b/scripts/3rd-party/backend.js index ea32cc31..1cedf516 100644 --- a/scripts/3rd-party/backend.js +++ b/scripts/3rd-party/backend.js @@ -276,14 +276,11 @@ const SmartAlbumID = Object.freeze({ /** * @typedef InitializationData * - * @property {number} status - `1`: unauthenticated, `2`: authenticated - * @property {boolean} admin - * @property {boolean} may_upload - * @property {boolean} is_locked + * @property {?User} user + * @property {{is_admin: boolean, is_locked: boolean, may_upload: boolean}} rights * @property {number} update_json - version number of latest available update * @property {boolean} update_available * @property {Object.} locale - * @property {string} [username] - only if user is not the admin; TODO: Change that * @property {ConfigurationData} config * @property {DeviceConfiguration} config_device */ diff --git a/scripts/main/album.js b/scripts/main/album.js index 7ac659c7..68d6671a 100644 --- a/scripts/main/album.js +++ b/scripts/main/album.js @@ -1393,15 +1393,15 @@ album.apply_nsfw_filter = function () { * @returns {boolean} */ album.isUploadable = function () { - if (lychee.admin) { + if (lychee.rights.is_admin) { return true; } - if (lychee.publicMode || !lychee.may_upload) { + if (lychee.publicMode || !lychee.rights.may_upload) { return false; } // TODO: Comparison of numeric user IDs (instead of names) should be more robust - return album.json === null || !album.json.owner_name || album.json.owner_name === lychee.username; + return album.json === null || (lychee.user !== null && album.json.owner_name === lychee.user.username); }; /** diff --git a/scripts/main/contextMenu.js b/scripts/main/contextMenu.js index 098e5d0c..be884698 100644 --- a/scripts/main/contextMenu.js +++ b/scripts/main/contextMenu.js @@ -25,7 +25,7 @@ contextMenu.add = function (e) { items.splice(1); } - if (!lychee.admin) { + if (!lychee.rights.is_admin) { // remove import from dropbox and server if not admin items.splice(3, 2); } else if (!lychee.dropboxKey || lychee.dropboxKey === "") { @@ -678,7 +678,7 @@ contextMenu.move = function (IDs, e, callback, kind = "UNSORTED", display_root = addItems(data.albums); } - if (data.shared_albums && data.shared_albums.length > 0 && lychee.admin) { + if (data.shared_albums && data.shared_albums.length > 0 && lychee.rights.is_admin) { items = items.concat({}); addItems(data.shared_albums); } @@ -717,7 +717,11 @@ contextMenu.sharePhoto = function (photoID, e) { { title: build.iconic("twitter", iconClass) + "Twitter", fn: () => photo.share(photoID, "twitter") }, { title: build.iconic("facebook", iconClass) + "Facebook", fn: () => photo.share(photoID, "facebook") }, { title: build.iconic("envelope-closed") + "Mail", fn: () => photo.share(photoID, "mail") }, - { title: build.iconic("dropbox", iconClass) + "Dropbox", visible: lychee.admin === true, fn: () => photo.share(photoID, "dropbox") }, + { + title: build.iconic("dropbox", iconClass) + "Dropbox", + visible: lychee.rights.is_admin === true, + fn: () => photo.share(photoID, "dropbox"), + }, { title: build.iconic("link-intact") + lychee.locale["DIRECT_LINKS"], fn: () => photo.showDirectLinks(photoID) }, { title: build.iconic("grid-two-up") + lychee.locale["QR_CODE"], fn: () => photo.qrCode(photoID) }, ]; @@ -782,12 +786,12 @@ contextMenu.config = function (e) { if (lychee.new_photos_notification) { items.push({ title: build.iconic("bell") + lychee.locale["NOTIFICATIONS"], fn: notifications.load }); } - if (lychee.admin) { + if (lychee.rights.is_admin) { items.push({ title: build.iconic("person") + lychee.locale["USERS"], fn: users.list }); } items.push({ title: build.iconic("key") + lychee.locale["U2F"], fn: u2f.list }); items.push({ title: build.iconic("cloud") + lychee.locale["SHARING"], fn: sharing.list }); - if (lychee.admin) { + if (lychee.rights.is_admin) { items.push({ title: build.iconic("align-left") + lychee.locale["LOGS"], fn: function () { diff --git a/scripts/main/header.js b/scripts/main/header.js index b10aabc0..774162ab 100644 --- a/scripts/main/header.js +++ b/scripts/main/header.js @@ -287,7 +287,7 @@ header.setMode = function (mode) { tabindex.makeUnfocusable(e); } - if (lychee.enable_button_add && lychee.may_upload) { + if (lychee.enable_button_add && lychee.rights.may_upload) { const e = $(".button_add", ".header__toolbar--albums"); e.show(); tabindex.makeFocusable(e); diff --git a/scripts/main/lychee.js b/scripts/main/lychee.js index b8b521b3..b7bb4624 100644 --- a/scripts/main/lychee.js +++ b/scripts/main/lychee.js @@ -18,22 +18,30 @@ const lychee = { public_photos_hidden: true, share_button_visible: false, /** - * Enable admin mode (multi-user) - * @type boolean - */ - admin: false, - /** - * Enable possibility to upload (multi-user) - * @type boolean + * The authenticated user or `null` if unauthenticated + * @type {?User} */ - may_upload: false, + user: null, /** - * Locked user (multi-user) - * @type boolean + * The rights granted by the backend */ - is_locked: false, - /** @type {?string} */ - username: null, + rights: { + /** + * Backend grants admin rights + * @type boolean + */ + is_admin: false, + /** + * Backend grants upload rights + * @type boolean + */ + may_upload: false, + /** + * Backend considers the user to be locked + * @type boolean + */ + is_locked: false, + }, /** * Values: * @@ -242,23 +250,21 @@ lychee.init = function (isFirstInitialization = true) { function (data) { lychee.parseInitializationData(data); - if (data.status === 2) { - // Logged in + if (data.user !== null || data.rights.is_admin) { + // Authenticated or no admin is registered leftMenu.build(); leftMenu.bind(); lychee.setMode("logged_in"); - // Show dialog when there is no username and password - // TODO: Refactor this. At least rename the flag `login` to something more understandable like `isAdminUserConfigured`, but rather re-factor the whole logic, i.e. the initial user should be created as part of the installation routine. + // Show dialog to create admin account, if no user is + // authenticated but admin rights are granted. + // TODO: Refactor the whole logic, i.e. the initial user should be created as part of the installation routine. // In particular it is completely insane to build the UI as if the admin user was successfully authenticated. // This might leak confidential photos to anybody if the DB is filled // with photos and the admin password reset to `null`. - if (data.config.login === false) settings.createLogin(); - } else if (data.status === 1) { - lychee.setMode("public"); + if (data.user === null && data.rights.is_admin) settings.createLogin(); } else { - loadingBar.show("error", "Error: Unexpected status"); - return; + lychee.setMode("public"); } if (isFirstInitialization) { @@ -277,6 +283,8 @@ lychee.init = function (isFirstInitialization = true) { * @returns {void} */ lychee.parseInitializationData = function (data) { + lychee.user = data.user; + lychee.rights = data.rights; lychee.update_json = data.update_json; lychee.update_available = data.update_available; @@ -295,23 +303,9 @@ lychee.parseInitializationData = function (data) { lychee.locale[key] = data.locale[key]; } - // Check status - // 0 = No configuration - // 1 = Logged out - // 2 = Logged in - if (data.status === 2) { - // Logged in - lychee.parsePublicInitializationData(data); + lychee.parsePublicInitializationData(data); + if (lychee.user !== null || lychee.rights.is_admin) { lychee.parseProtectedInitializationData(data); - - lychee.may_upload = data.admin || data.may_upload; - lychee.admin = data.admin; - lychee.is_locked = data.is_locked; - lychee.username = data.username; - } else if (data.status === 1) { - lychee.parsePublicInitializationData(data); - } else { - // should not happen. } }; @@ -833,10 +827,10 @@ lychee.setTitle = function (title = "", editable = false) { * @param {string} mode - one out of: `public`, `view`, `logged_in` */ lychee.setMode = function (mode) { - if (lychee.is_locked) { + if (lychee.rights.is_locked) { $("#button_settings_open").remove(); } - if (!lychee.may_upload) { + if (!lychee.rights.may_upload) { $("#button_sharing").remove(); $(document) @@ -855,7 +849,7 @@ lychee.setMode = function (mode) { .unbind(["command+backspace", "ctrl+backspace"]) .unbind(["command+a", "ctrl+a"]); } - if (!lychee.admin) { + if (!lychee.rights.is_admin) { $("#button_users, #button_logs, #button_diagnostics").remove(); } diff --git a/scripts/main/multiselect.js b/scripts/main/multiselect.js index 092144d6..3c6f351c 100644 --- a/scripts/main/multiselect.js +++ b/scripts/main/multiselect.js @@ -80,7 +80,7 @@ multiselect.toggleItem = function (object, id) { */ multiselect.addItem = function (object, id) { if (album.isSmartID(id) || album.isSearchID(id)) return; - if (!lychee.admin && albums.isShared(id)) return; + if (!lychee.rights.is_admin && albums.isShared(id)) return; if (multiselect.isSelected(id).selected === true) return; let isAlbum = object.hasClass("album"); diff --git a/scripts/main/settings.js b/scripts/main/settings.js index c7bf9960..44679c11 100644 --- a/scripts/main/settings.js +++ b/scripts/main/settings.js @@ -33,6 +33,14 @@ settings.createLogin = function () { return true; }; + /** + * @param {User} updatedAdminUser + * @returns {void} + */ + const successHandler = function (updatedAdminUser) { + lychee.user = updatedAdminUser; + }; + /** * @typedef SetLoginDialogResult * @@ -72,7 +80,7 @@ settings.createLogin = function () { password, }; - api.post("Settings::setLogin", params, null, null, errorHandler); + api.post("Settings::setLogin", params, successHandler, null, errorHandler); }; const msg = ` @@ -194,11 +202,16 @@ settings.changeLogin = function (params) { $("input[name=confirm]").removeClass("error"); } - api.post("Settings::updateLogin", params, function () { - $("input[name]").removeClass("error"); - loadingBar.show("success", lychee.locale["SETTINGS_SUCCESS_LOGIN"]); - view.settings.content.clearLogin(); - }); + api.post( + "Settings::updateLogin", + params, + /** @param {User} updatedUser */ function (updatedUser) { + $("input[name]").removeClass("error"); + loadingBar.show("success", lychee.locale["SETTINGS_SUCCESS_LOGIN"]); + view.settings.content.clearLogin(); + lychee.user = updatedUser; + } + ); }; /** diff --git a/scripts/main/view.js b/scripts/main/view.js index a22e6fe0..14f3b018 100644 --- a/scripts/main/view.js +++ b/scripts/main/view.js @@ -79,7 +79,7 @@ view.albums = { html += build.divider(album.owner_name); current_owner = album.owner_name; } - return html + build.album(album, !lychee.admin); + return html + build.album(album, !lychee.rights.is_admin); }, ""); if (smartData === "" && tagAlbumsData === "" && albumsData === "" && sharedData === "") { @@ -491,7 +491,7 @@ view.album = { // }, targetRowHeight: parseFloat($(".photo").css("--lychee-default-height")), }); - // if (lychee.admin) console.log(layoutGeometry); + // if (lychee.rights.is_admin) console.log(layoutGeometry); $(".justified-layout").css("height", layoutGeometry.containerHeight + "px"); $(".justified-layout > div").each(function (i) { if (!layoutGeometry.boxes[i]) { @@ -1034,7 +1034,7 @@ view.settings = { init: function () { view.settings.clearContent(); view.settings.content.setLogin(); - if (lychee.admin) { + if (lychee.rights.is_admin) { view.settings.content.setSorting(); view.settings.content.setDropboxKey(); view.settings.content.setLang();