Skip to content

Add profile picture library with multi-upload and dataset propagation#116

Merged
vincentmakes merged 4 commits into
mainfrom
claude/fix-profile-picture-toggle-p3KEw
Apr 17, 2026
Merged

Add profile picture library with multi-upload and dataset propagation#116
vincentmakes merged 4 commits into
mainfrom
claude/fix-profile-picture-toggle-p3KEw

Conversation

@vincentmakes

Copy link
Copy Markdown
Owner

Description

Implements a profile picture library system that allows users to upload and manage multiple profile pictures, similar to the existing company logo library. Key features include:

  • Picture library: Upload multiple profile pictures stored as profile_<timestamp>.<ext> in the uploads directory
  • Picture picker: Reuse any previously uploaded picture from a grid picker without re-uploading
  • Global propagation toggle: New picture_propagate flag (default: enabled) that mirrors the active picture filename into all saved dataset snapshots when toggled on
  • Dataset isolation: When propagation is off, each dataset retains its own picture independently
  • Legacy migration: Automatically promotes the old uploads/picture.jpeg into the new library format on first run
  • Public API exposure: Profile picture fields (profile_picture_enabled, picture_filename) are now exposed in public /api/profile and /api/cv endpoints

Type of Change

  • New feature (non-breaking change that adds functionality)

Implementation Details

Backend Changes (src/server.js)

  • Added picture_filename and picture_propagate columns to the profile table with migrations
  • New endpoints:
    • POST /api/profile/picture — upload a new picture (stored with timestamp)
    • PUT /api/profile/picture/select — reuse an existing picture from the library
    • GET /api/profile-pictures — list all pictures with in_use flag
    • DELETE /api/profile-pictures/:filename — delete unused pictures (returns 409 if in use)
  • propagateProfilePictureToDatasets() helper mirrors filename changes into all saved dataset snapshots when enabled
  • Path traversal validation via isValidProfilePictureName() to prevent directory escape attacks
  • Public endpoints updated to include picture fields in responses

Frontend Changes (public/shared/admin.js)

  • Profile form now shows picture picker grid with delete buttons for unused entries
  • "Use Existing" button toggles the picker grid
  • "Apply this picture to all datasets" toggle controls the propagation behavior
  • uploadProfilePicture() refactored to handle three modes: new upload, reuse from library, or delete
  • showPicturePicker(), selectExistingPicture(), deleteUnusedPicture() functions manage library interactions

Public Display (public-readonly/index.html, public/shared/scripts.js)

  • Profile picture display now uses picture_filename from the database instead of hardcoded picture.jpeg
  • Respects profile_picture_enabled flag to show/hide the picture container
  • Open-to-Work badge positioning adjusted to work with the new picture system

Internationalization

  • Added 3 new i18n keys to all 8 locale files:
    • form.apply_picture_globally
    • form.delete_picture
    • form.no_pictures_available

Tests

  • Added comprehensive test suite (13 tests) covering:
    • Public API exposure of picture fields
    • Dataset save/load preservation of picture settings
    • Propagation behavior (on/off)
    • Picture library listing with in_use flag
    • Deletion constraints (409 when in use, 200 for orphans)
    • Picture selection and path traversal protection

Checklist

  • Tests pass (npm test — 13 new tests added to backend.test.js)
  • Version bumped: package.json (1.31.0 → 1.32.0), version.json (1.31.0 → 1.32.0)
  • CHANGELOG.md updated with new entry under [1.32.0]
  • All user-visible strings use t() function and i18n keys
  • New i18n keys added to all 8 locale files
  • User-provided filenames escaped with encodeURIComponent() in URLs
  • Path traversal validation implemented

https://claude.ai/code/session_01PtvFP46WXZ9FsPrsq9nmTu

claude added 4 commits April 17, 2026 16:48
Public site now honors the "Show profile picture" toggle across /, /<lang>,
and /v/<slug>. Also reshapes the single-file picture model into a library
modeled on the existing logo system so users can:

- Upload multiple pictures and pick any of them from a grid
- Enable "Apply to all datasets" (default on) to mirror the current picture
  across every saved dataset snapshot
- Disable the toggle to keep per-dataset pictures; language siblings added
  to a dataset inherit the sibling's picture via the existing sibling copy
- Delete unused library entries; in-use entries return 409
- Reuse pictures via a new `/api/profile-pictures` library plus
  `/api/profile/picture/select` endpoint

The legacy `uploads/picture.jpeg` is promoted to a first-class library
entry on first run so existing installs keep their picture.

https://claude.ai/code/session_01PtvFP46WXZ9FsPrsq9nmTu
When the user uploads, selects, or removes a profile picture while editing
a localized dataset, every language sibling in the same language_group now
receives the same filename even when the "Apply to all datasets" toggle is
off. Unrelated datasets stay on their own picture.

The admin now passes the active dataset id with each picture operation so
the server can look up the sibling group and mirror the change.

https://claude.ai/code/session_01PtvFP46WXZ9FsPrsq9nmTu
Previously, enabling "Open to Work" while disabling "Show profile picture"
left the colored gradient circle visible in the header, because the OTW
overlay was forcing the profile-image container to `display: flex` to give
the badge a host element.

The OTW badge is decoration on the picture, so it no longer renders when
the picture is hidden. Disabling the picture now really removes the entire
header circle on both admin and public-readonly renderers.

https://claude.ai/code/session_01PtvFP46WXZ9FsPrsq9nmTu
Collapse 1.32.0 / 1.32.1 / 1.32.2 into a single 1.32.0 entry so the
feature and its follow-up fixes ship as one version. No functional change.

https://claude.ai/code/session_01PtvFP46WXZ9FsPrsq9nmTu
@vincentmakes vincentmakes merged commit afa5849 into main Apr 17, 2026
3 checks passed
@vincentmakes vincentmakes deleted the claude/fix-profile-picture-toggle-p3KEw branch April 17, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants