Commit Graph

826 Commits

Author SHA1 Message Date
Paul Nothaft e382aed4d1 Merge pull request #394 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Failing after 5m56s
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Failing after 6m34s
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.39.1-beta.0
v3.39.1-beta.0
2026-05-04 22:18:29 +02:00
github-actions[bot] ac05230867 chore(beta): release 3.39.1-beta.0 2026-05-04 19:37:59 +00:00
Paul Nothaft c60ab74ae2 Merge pull request #393 from the-luap/docs/contributors
docs(readme): add Contributors section with @Luca-Timo and @Rekoo-PS
2026-05-04 21:37:37 +02:00
Paul Nothaft dbe0a3055b docs(readme): add Contributors section with @Luca-Timo and @Rekoo-PS
The Acknowledgments block had a generic "thanks to all contributors"
line but no actual recognition by name. Two people in particular have
moved the project meaningfully forward and should be called out:

- @Luca-Timo — code contributor across multi-arch Docker, the external-
  URL CMS toggle, folder tree picker, admin email picker, self-hosted
  webfonts, the gallery header/banner decoupling, and typed-API
  refactors. Consistent quality.

- @Rekoo-PS — bug reporter and feedback loop. Filed the issues that
  drove the login-loop fix, gallery loading skeleton, redirection
  cleanup, mobile lightbox overhaul, admin events search-counter fix,
  photo-count column, and bulk-delete workflow. Also a BuyMeACoffee
  supporter.

Closes the implicit recognition gap and sets up the section so future
contributors can be added with a one-line PR.
2026-05-04 21:35:27 +02:00
Paul Nothaft 99392c5888 Merge pull request #392 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Failing after 6m9s
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Failing after 6m40s
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.39.0-beta.0
v3.39.0-beta.0
2026-05-04 21:28:06 +02:00
github-actions[bot] 6fe1d8de9e chore(beta): release 3.39.0-beta.0 2026-05-04 19:16:41 +00:00
Paul Nothaft 1f1a856083 Merge pull request #385 from Luca-Timo/beta
feat(gallery): decouple header style from layout, add banner option
2026-05-04 21:16:13 +02:00
Paul Nothaft d0d283a13e Merge pull request #391 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Failing after 6m30s
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Failing after 6m39s
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.38.0-beta.0
v3.38.0-beta.0
2026-05-04 21:01:06 +02:00
github-actions[bot] 0a48646529 chore(beta): release 3.38.0-beta.0 2026-05-04 19:00:37 +00:00
Paul Nothaft 647aea21ae Merge pull request #389 from the-luap/feat/events-bulk-delete
feat(events): bulk delete with password confirmation (#384)
2026-05-04 21:00:06 +02:00
Paul Nothaft 7491eb21c4 Merge pull request #388 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Failing after 6m28s
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Failing after 7m35s
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.37.0-beta.0
v3.37.0-beta.0
2026-05-04 20:59:53 +02:00
Paul Nothaft 48d538f94f feat(events): bulk delete with password confirmation (#384)
Adds the bulk-delete half of #384 — admins can select multiple
events from the list and delete them in one batch, gated by
re-entering their password.

## Why password confirmation

Bulk delete is destructive and irreversible (cascades across 5 DB
tables and 3 filesystem paths per event). Re-entering the password
matches the pattern already used by /auth/admin/change-password and
makes accidental clicks much harder than a plain "type DELETE to
confirm" — the muscle-memory required to type your real password is
a stronger gate than typing a literal word.

## Changes

### Backend (adminEvents.js)

- Extracted the per-event cascade-delete logic into a module-private
  `deleteEventCascade(eventId, adminContext)` helper. The DELETE /:id
  route now calls it instead of inlining 60 lines of cascade — same
  behaviour, no drift between the per-event and bulk paths.
- New `POST /admin/events/bulk-delete`. Body: `{ eventIds, password }`.
  Permission: `events.delete`.
  - Validates `eventIds` array length (1–100) and that each id is an
    integer. The 100-cap keeps request time bounded; the per-event
    cascade touches DB + filesystem so 1000 events at once would risk
    timing out the request.
  - Verifies `password` against the calling admin's bcrypt hash via
    `bcrypt.compare()` (same as /auth/admin/change-password). Wrong
    password → 401 `{ error, code: 'INVALID_PASSWORD' }` and no
    events are touched.
  - Loops via `deleteEventCascade`, returns
    `{ results: { successful, failed } }` with the same shape as
    /bulk-archive so the frontend can show partial-failure feedback.
  - Logs `bulk_delete_completed` activity with totals.

### Frontend

- `events.service.ts`: `bulkDeleteEvents(eventIds, password)`.
- New `BulkDeleteModal.tsx`. Red/destructive variant of the
  bulk-archive modal:
  - Lists the events to be deleted (so the admin can verify).
  - Password input with show/hide toggle, autofocus, Enter-to-submit.
  - Inline `passwordError` prop surfaces the 401 INVALID_PASSWORD
    response without losing the modal state — admin can retry
    without re-typing the event list.
  - "Processing" state replaces the form with a spinner + "Deleting
    N events. This may take a few minutes — please don't close this
    window." (i18n) so admins know not to abandon the page during
    a slow operation.
- `EventsListPage.tsx`: "Delete Selected" button next to "Archive
  Selected" in the bulk-actions bar (red-styled to signal danger),
  bulkDeleteMutation that maps the 401 to the modal's inline error
  and any other failure to a generic toast.

### i18n

12 new keys under `events.bulkDelete.*` in all 5 locales
(en/de/nl/pt/ru): title, warning, password label/placeholder/help,
submit, processing, incorrectPassword, successAll, successPartial,
errorGeneric, plus `events.deleteSelected` for the button. Hand-
written for de; nl/pt/ru should get a native-speaker pass at some
point but read naturally.

### Verified

- `npx tsc --noEmit` clean
- `npx eslint` clean on every touched file (4 pre-existing errors in
  adminEvents.js for unused vars unrelated to this PR)
- All 5 locale JSON files parse cleanly
- `node -e "require('./src/routes/adminEvents')"` loads the module

Closes the bulk-delete half of #384. The Photos-column half lands
separately in PR #387.
2026-05-04 20:56:00 +02:00
github-actions[bot] 67999999d8 chore(beta): release 3.37.0-beta.0 2026-05-04 18:52:09 +00:00
Paul Nothaft d561db802b Merge pull request #387 from the-luap/feat/events-photos-column
feat(events): add Photos column to admin events list (#384)
2026-05-04 20:51:44 +02:00
Paul Nothaft ffb4318a1f feat(events): add Photos column to admin events list (#384)
The admin events table didn't surface how many photos each event
contained — admins had to click into the event to find out. The
backend already computes `photo_count` for every row in the
GET /admin/events list response (adminEvents.js:794-796), so this
is a frontend-only display change.

- Insert a "Photos" column between Date and Status — groups with
  the "what's in this event" info.
- Right-aligned, tabular-nums for clean numeric alignment in the
  column.
- Reuses the existing `events.photos` i18n key already shipped in
  all 5 locales for the EventDetailsPage tab list ("Fotos" / etc.) —
  no new translations needed.
- Updates the empty-state colSpan from 7 to 8.

Closes the column-add half of #384. The bulk-delete request from
the same issue lands separately.
2026-05-04 20:47:13 +02:00
Luca 894e151255 i18n(gallery): nl/ru wording polish for standard header style 2026-05-04 16:58:26 +02:00
Luca 05dadff493 fix(gallery): preserve sidebar controlsStyle on banner migration 2026-05-04 16:58:17 +02:00
Luca 91ad6bba99 style(theme-customizer): match header-style picker grid to layout picker (3 cols) 2026-05-04 15:48:12 +02:00
Luca 045e9ea486 fix(gallery): default controls to inline for every layout 2026-05-04 15:46:41 +02:00
Luca 24d727752c Merge pull request #1 from Luca-Timo/feat/decouple-gallery-header
feat(gallery): decouple header style from layout, add banner option
2026-05-04 15:30:52 +02:00
Paul Nothaft 0adec25fe7 Merge pull request #382 from Luca-Timo/refactor/external-media-types
refactor(events): type external-media list response, drop any casts
2026-05-04 14:46:35 +02:00
Luca d823dcda26 Merge branch 'beta' into refactor/external-media-types 2026-05-04 14:40:01 +02:00
Luca 0bd61be5a6 i18n(gallery): translate banner header strings (nl/pt/ru) 2026-05-04 14:34:55 +02:00
Luca aff29c91bb feat(gallery): decouple header style from layout, add banner option 2026-05-04 14:34:42 +02:00
Paul Nothaft 4d99eb672d Merge pull request #383 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Failing after 6m15s
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Failing after 6m31s
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.36.0-beta.0
v3.36.0-beta.0
2026-05-04 13:44:35 +02:00
github-actions[bot] 66281f9790 chore(beta): release 3.36.0-beta.0 2026-05-04 11:33:17 +00:00
Paul Nothaft 3fe8e61bd1 Merge pull request #379 from Luca-Timo/feat/admin-email-picker
feat(events): prefill admin email + admin picker on event creation
2026-05-04 13:32:53 +02:00
Paul Nothaft 06f2b75ec3 Merge pull request #381 from the-luap/chore/external-folder-picker-types
chore(events): type FolderTreeNode entries with ExternalEntry
2026-05-04 13:31:11 +02:00
Luca ffbb0e659f refactor(events): type external-media list response, drop any casts 2026-05-04 12:28:46 +02:00
Paul Nothaft 98c6f6cf06 chore(events): type FolderTreeNode entries with ExternalEntry
Follow-up to PR #378 — drops the (e: any) / (d: any) casts in the
external-folder-tree picker. ExternalEntry is already exported from
externalMedia.service.ts; the call site just wasn't using it.

- Import the type alongside the service.
- Annotate the dirs filter callback so `e.type` is the union 'dir' |
  'file' instead of any.
- Drop the (d: any) annotation from the map — TypeScript infers
  ExternalEntry from the typed `dirs` array.

No behaviour change, no test impact. `npx tsc --noEmit` clean,
`npx eslint` clean.
2026-05-04 12:24:21 +02:00
Paul Nothaft bfd7169fc4 Merge pull request #380 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Failing after 5m41s
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Failing after 6m35s
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.35.0-beta.0
v3.35.0-beta.0
2026-05-04 12:21:35 +02:00
github-actions[bot] 7e4f1acb88 chore(beta): release 3.35.0-beta.0 2026-05-04 10:21:13 +00:00
Paul Nothaft cdd40acb45 Merge pull request #378 from Luca-Timo/beta
feat(events): tree view for external media folder picker
2026-05-04 12:20:54 +02:00
Luca 40d23e24cb i18n(events): translate admin email picker strings (nl/pt/ru) 2026-05-04 12:10:23 +02:00
Luca ee56b6762f feat(events): prefill admin email + admin picker on event creation 2026-05-04 12:10:23 +02:00
Luca bd42ee1ce0 fix(events): match scrollbar to theme in external folder tree picker 2026-05-04 11:30:46 +02:00
Luca 954ab00495 i18n(events): translate external folder picker strings (nl/pt/ru) 2026-05-04 11:02:00 +02:00
Luca f927b09c70 feat(events): tree view for external media folder picker 2026-05-04 11:01:49 +02:00
Paul Nothaft 048870804f Merge pull request #377 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Failing after 5m54s
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Failing after 6m42s
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.34.2-beta.0
v3.34.2-beta.0
2026-05-04 09:15:29 +02:00
github-actions[bot] 13e3a05386 chore(beta): release 3.34.2-beta.0 2026-05-04 07:14:40 +00:00
Paul Nothaft 3ab8a64a24 Merge pull request #376 from the-luap/fix/ffmpeg-on-alpine
fix(docker): install system ffmpeg on Alpine, drop broken bundled binary
2026-05-04 09:14:16 +02:00
Paul Nothaft 96818c7ae8 fix(docker): install system ffmpeg on Alpine, drop broken bundled binary
Video uploads on production fail with "missing ffmpeg" because the
backend container ships nothing usable for the video pipeline.

Two compounding causes:

1. **Alpine + glibc mismatch.** The npm `@ffmpeg-installer/ffmpeg`
   dependency added with the video-support PR (commit 68a9dc5)
   ships per-platform binaries via optionalDependencies. The Linux
   binaries are built against glibc, but the backend image runs on
   `node:22-alpine` (musl libc) — known to either fail to execute
   or fail on shared-library lookups on Alpine.

2. **`ffprobe` missing entirely.** `@ffmpeg-installer/ffmpeg`
   bundles only the `ffmpeg` binary. There's a separate
   `@ffprobe-installer/ffprobe` package that the codebase never
   depended on. But `videoProcessor.js:21` calls
   `ffmpeg.ffprobe(videoPath, …)` — the very first step of the
   video pipeline shells out to a `ffprobe` binary that doesn't
   exist in the image. Even if (1) worked, every video upload
   would 500 here.

The fix is to install Alpine's `ffmpeg` package via apk. It ships
both `ffmpeg` and `ffprobe` built natively against musl, ~70MB
extra image size, single line in the Dockerfile, no per-arch
handling needed (apk pulls the right binary for both linux/amd64
and linux/arm64 — works with the multi-arch infra from #349).

- `backend/Dockerfile`: add `ffmpeg` to the apk install line.
- `backend/Dockerfile.dev`: same for dev parity.
- `backend/src/services/videoProcessor.js`: remove the
  `setFfmpegPath(require('@ffmpeg-installer/ffmpeg').path)` line
  — without removing it, fluent-ffmpeg would prefer the broken
  bundled binary over the working apk one. Letting fluent-ffmpeg
  fall back to PATH lookup picks up the apk binary in the
  container and the developer's locally-installed binary on dev
  hosts (Homebrew on macOS, apt on Debian).
- `backend/package.json`: drop the now-unused
  `@ffmpeg-installer/ffmpeg` dependency. `npm install` removes
  2 packages from the lockfile.

Verified: `videoProcessor.js` still loads cleanly (`node -e
"require('./src/services/videoProcessor')"`); lint clean.
2026-05-04 09:04:38 +02:00
Paul Nothaft 8f2639bdca Merge pull request #375 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Failing after 6m20s
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Failing after 6m47s
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.34.1-beta.0
v3.34.1-beta.0
2026-05-04 00:19:37 +02:00
github-actions[bot] eb6791792e chore(beta): release 3.34.1-beta.0 2026-05-03 22:18:02 +00:00
Paul Nothaft 08d046276b Merge pull request #374 from the-luap/fix/cms-external-url-i18n-and-api-shape
fix(cms): nl/pt/ru i18n + gate external_url in public response
2026-05-04 00:17:40 +02:00
Paul Nothaft bce5c1f725 fix(cms): nl/pt/ru i18n + gate external_url in public response
Two follow-ups to PR #372 (external-URL toggle for imprint /
privacy CMS pages):

1. **i18n.** PR #372 added 6 new `cms.*` keys to the en + de
   locales but the project ships 5 locales total. Adds the missing
   nl / pt / ru translations so the admin CMS page renders in the
   active language for those users instead of falling back to
   English literals next to the German/Dutch/Portuguese/Russian
   surrounding strings.

2. **API shape.** `publicCMS.js` returned `external_url`
   unconditionally — even when `use_external_url` is false the URL
   value was still emitted in the public response. The frontend
   correctly gated on both flags so it worked, but the API surface
   was leaking a value the admin had explicitly disabled. The
   value still lives in the DB (so the toggle can be flipped back
   on without losing it), but the public endpoint now returns
   `null` whenever the toggle is off.

   Note: kept the existing `logo_url` shape unchanged. Its semantics
   are different — null means "fall back to global branding" and
   consumers rely on always having the field, so emitting it
   unconditionally is intentional there.

No frontend change needed: both `GalleryLayout` and `LegalPage`
already gate on `use_external_url && external_url`, so the
short-circuit handles `external_url: null` correctly.
2026-05-04 00:14:07 +02:00
Paul Nothaft ccd3fd9349 Merge pull request #373 from the-luap/release-please--branches--beta
Build and Push Docker Images / build-backend (linux/amd64, ubuntu-latest) (push) Failing after 6m20s
Build and Push Docker Images / build-frontend (linux/amd64, ubuntu-latest) (push) Failing after 6m26s
Build and Push Docker Images / build-backend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build and Push Docker Images / merge-frontend (push) Has been cancelled
Build and Push Docker Images / summary (push) Has been cancelled
chore(beta): release 3.34.0-beta.0
v3.34.0-beta.0
2026-05-04 00:11:41 +02:00
github-actions[bot] cf04c0b2dc chore(beta): release 3.34.0-beta.0 2026-05-03 22:11:01 +00:00
Paul Nothaft b2c8161a43 Merge pull request #372 from Luca-Timo/beta
feat(cms): add external URL toggle for imprint and privacy pages
2026-05-04 00:10:44 +02:00
Paul Nothaft aade003564 Merge pull request #371 from the-luap/i18n/password-reset-modal
i18n(events): translate PasswordResetModal across 5 locales
2026-05-03 23:29:09 +02:00