fix(frontend): stop a parked photo being stranded for the session, and fix an SSE id

A parked upload has three ways to be released, and two were weaker than the
toast that promises "wird gesendet, sobald die Sperre aufgehoben ist":

* The live user-shown / event-opened events only reach a tab with an open
  stream, and streams are opened by /feed, /diashow, /export, /host and
  /admin — NOT /upload, which is exactly where the toast sends the guest to
  watch their queue.
* The boot-time release ran once and swallowed any failure, so a single
  failed request on venue wifi — the condition the whole parking mechanism
  exists for — skipped it for the entire session, leaving the row reading
  "Du bist gesperrt." after the ban was long lifted.

Now retried once. Deliberately NOT on a 401: api.get already answered that by
clearing auth and redirecting to /join, so a second attempt can only fire a
second redirect two seconds later, by which time the guest may have navigated
away. (That is not hypothetical — it made an existing browser-chaos spec fail
while I was writing this.) Guarded rather than an early return, so the SSE
listener registrations below still run.

Also: noteDelivered mapped upload-processed to p.id, but that payload carries
upload_id, so it recorded nothing — the docstring claimed a property the code
did not have. And it recorded user-shown against a `carried` clause that only
ever means "hidden", where it could only suppress a later genuine signal.
This commit is contained in:
fabi
2026-08-12 09:15:40 +02:00
parent 9f239882ac
commit 5aa2b2e886
2 changed files with 47 additions and 5 deletions

View File

@@ -367,11 +367,18 @@ function noteDelivered(eventName: string, data: string): void {
// Mirrors the three clauses in `carried`: uploads by upload id, deletions by upload id,
// ban-hides by user id.
const relevant =
eventName === 'new-upload' || eventName === 'upload-processed'
eventName === 'new-upload'
? p.id
: eventName === 'upload-deleted'
: // `upload-processed` carries `upload_id`, not `id` (see compression.rs) — reading
// `p.id` recorded nothing at all, so this branch quietly did the opposite of what
// the comment above claims. Harmless today only because the delta cursor is
// anchored by `new-upload`, which is not a property worth depending on.
eventName === 'upload-processed' || eventName === 'upload-deleted'
? (p.upload_id ?? p.id)
: eventName === 'user-hidden' || eventName === 'user-shown'
: // Only `user-hidden` has a matching clause in `carried` (`hidden_user_ids` comes
// from `uploads_hidden = TRUE`). Recording an UNBAN's user id could only ever
// suppress a later genuine signal, so it is deliberately not recorded.
eventName === 'user-hidden'
? p.user_id
: undefined;
if (typeof relevant === 'string') rememberDelivered(relevant);