fix(gallery): no Logout button on galleries that don't require a password (#1149) (#1152)

showLogout was hard-coded true, so a gallery with no password showed a Logout button. Logging out of it is meaningless — no credential to drop, nothing to return to — and it stranded the visitor: GalleryPage's auto-login is a one-shot latch, so clearing the session left the page on its skeleton until a manual reload. That is the 'turns blank' in the report.

The button is gated on requiresPassword || isClient || viaCustomer at both call sites. The full-page layouts render it on the callback being present rather than on a flag, so withholding the callback is how the gate reaches them.

Session kind now comes from /auth/session rather than sessionStorage, which is per-tab while the cookie is per-browser: a gallery reopened in a second tab lost 'client' while the backend kept serving it as one. viaCustomer marks a portal token, which bypasses reveal mode and so is a credential that does not look like one.

The public-gallery branch no longer returns the skeleton unconditionally — once auto-login has run and left us unauthenticated it shows the reason and a Retry. That state was otherwise unrecoverable, and it also swallowed loginError entirely.

Merged with admin privileges: the author cannot self-approve.
This commit is contained in:
Paul Nothaft
2026-08-23 22:06:47 +02:00
committed by GitHub
parent b581267031
commit e4a8be8e7e
5 changed files with 156 additions and 9 deletions
+11
View File
@@ -819,6 +819,17 @@ router.get('/session', async (req, res) => {
user: decoded.username || decoded.eventSlug,
eventSlug: decoded.eventSlug,
adminUsername: decoded.username,
// What KIND of gallery session this cookie is (#1149). The frontend
// kept this in sessionStorage, which is per-tab: reopening a gallery
// in a second tab lost 'client' while the cookie — and therefore the
// backend — still treated it as one. Reported from the token so a
// restored session knows what it actually is.
//
// viaCustomer marks a portal-minted token. It runs at accessLevel
// 'guest' but bypasses reveal mode, so it is a credential even though
// it does not look like one.
accessLevel: decoded.type === 'gallery' ? (decoded.accessLevel || 'guest') : undefined,
viaCustomer: decoded.type === 'gallery' ? decoded.via === 'customer' : undefined,
// Full admin payload (or null) — lets the SPA hydrate its user
// state after a redirect-established session (SSO, #798) where no
// login JSON response ever reached it.