fix(settings): confirm profile-picture upload and refresh the preview (LC-347) #365

Merged
longjacksonle merged 3 commits from fix/lc-347-avatar-upload-feedback into main 2026-06-19 04:21:43 +02:00

Fixes LC-347.

Problem

Uploading a profile picture at /settings gave no signal it worked: no success message, and the avatar preview looked unchanged, so it read as a failure even though the upload succeeded server-side.

Root causes (both confirmed in code)

  1. No success feedback. routes::settings::post_profile redirected to /settings instead of /settings?saved=1, so the existing "Saved." flash (used by post_language / post_appearance) never fired.
  2. Stale preview. The preview <img src="/avatars/{id}?v={asset_version}"> was keyed by asset_version, a build-time constant that never changes on upload, while routes::avatar::get_avatar serves Cache-Control: max-age=300. The browser kept showing the cached old image for up to five minutes.

Fix

  • post_profile redirects to /settings?saved=1.
  • The preview is cache-busted by the avatar file's mtime (new avatar_cache_key helper, surfaced as UserSettingsPage.avatar_version), so the new image loads immediately.

Tests

New server/tests/routes_settings_profile.rs:

  • avatar_upload_redirects_to_saved_flash - POST multipart avatar returns 303 to /settings?saved=1 and persists avatar_ext.
  • settings_avatar_preview_cache_busts_not_asset_version - after upload the rendered <img> is no longer keyed by asset_version (?v=test).

just test and just test-saas both green.

Out of scope (noted in LC-347)

Inline form errors for the wrong-format / over-1-MiB cases (currently a full-page styled error), and the shared static-asset_version cache-buster on other avatar render sites (sidebar self, message author rows).

Fixes LC-347. ## Problem Uploading a profile picture at `/settings` gave no signal it worked: no success message, and the avatar preview looked unchanged, so it read as a failure even though the upload succeeded server-side. ## Root causes (both confirmed in code) 1. **No success feedback.** `routes::settings::post_profile` redirected to `/settings` instead of `/settings?saved=1`, so the existing "Saved." flash (used by `post_language` / `post_appearance`) never fired. 2. **Stale preview.** The preview `<img src="/avatars/{id}?v={asset_version}">` was keyed by `asset_version`, a build-time constant that never changes on upload, while `routes::avatar::get_avatar` serves `Cache-Control: max-age=300`. The browser kept showing the cached old image for up to five minutes. ## Fix - `post_profile` redirects to `/settings?saved=1`. - The preview is cache-busted by the avatar file's mtime (new `avatar_cache_key` helper, surfaced as `UserSettingsPage.avatar_version`), so the new image loads immediately. ## Tests New `server/tests/routes_settings_profile.rs`: - `avatar_upload_redirects_to_saved_flash` - POST multipart avatar returns 303 to `/settings?saved=1` and persists `avatar_ext`. - `settings_avatar_preview_cache_busts_not_asset_version` - after upload the rendered `<img>` is no longer keyed by `asset_version` (`?v=test`). `just test` and `just test-saas` both green. ## Out of scope (noted in LC-347) Inline form errors for the wrong-format / over-1-MiB cases (currently a full-page styled error), and the shared static-`asset_version` cache-buster on other avatar render sites (sidebar self, message author rows).
fix(settings): confirm profile-picture upload and refresh the preview (LC-347)
All checks were successful
check-secrets / TruffleHog (push) Successful in 3s
check-secrets / Kingfisher (push) Successful in 4s
check-secrets / Nosey parker (push) Successful in 5s
e573216643
Uploading a profile picture gave no signal that it worked: no success message, and the avatar preview appeared unchanged, so it read as a failure even though the upload succeeded.

Two causes. First, `post_profile` redirected to `/settings` rather than `/settings?saved=1`, so the existing "Saved." flash (used by `post_language` / `post_appearance`) never fired. Second, the preview `<img src="/avatars/{id}?v={asset_version}">` was keyed by `asset_version`, a build-time constant that never changes on upload, while the avatar route serves `Cache-Control: max-age=300`; the browser therefore showed the cached old image for up to five minutes.

`post_profile` now redirects to `/settings?saved=1`, and the preview is cache-busted by the avatar file's mtime (new `avatar_cache_key` helper, surfaced as `UserSettingsPage.avatar_version`) so the new image loads immediately. Adds `routes_settings_profile.rs` covering the `?saved=1` redirect and that the preview URL is no longer keyed by `asset_version`.

Out of scope (noted in LC-347): inline form errors for the wrong-format / over-1-MiB cases, and the shared static-`asset_version` cache-buster on other avatar render sites (sidebar self, message rows).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chore: drop accidental .claude/scheduled_tasks.lock change from LC-347
All checks were successful
check-secrets / Kingfisher (push) Successful in 4s
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Nosey parker (push) Successful in 4s
7beca2ae98
Merge remote-tracking branch 'origin/main' into fix/lc-347-avatar-upload-feedback
All checks were successful
check-secrets / Nosey parker (push) Successful in 4s
check-secrets / Kingfisher (push) Successful in 5s
check-secrets / Nosey parker (pull_request) Successful in 3s
check-secrets / Kingfisher (pull_request) Successful in 4s
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / TruffleHog (pull_request) Successful in 10s
Create release / Create release from merged PR (pull_request) Has been skipped
Check / clippy + fmt + tests (pull_request) Successful in 6m41s
797916bf44
longjacksonle deleted branch fix/lc-347-avatar-upload-feedback 2026-06-19 04:21:44 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!365
No description provided.