Fix 500 when removing a profile picture - #96
Merged
Conversation
Clearing the avatar picker submits an empty string, which ConvertEmptyStringsToNull hands to ProfileController as null. `users.avatar` is NOT NULL with an `avatar.png` default, so saving that null raised an integrity violation and the profile page returned a 500: the picture was never removed and no error surfaced to the user. Removing a picture now falls back to the default placeholder rather than null, and the media link is cleared as well as set, so avatar_media_id no longer keeps pointing at media that no longer represents the user. An update that omits the avatar field entirely still leaves the existing picture alone. The placeholder value moves into User::DEFAULT_AVATAR with a hasCustomAvatar() helper, and the profile form treats it as empty so a user with no picture sees the placeholder icon instead of a clear button with nothing to clear.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #94.
Root cause
users.avatarisvarchar(255) NOT NULL DEFAULT 'avatar.png'. Clearing the MediaPicker submits an empty string, and Laravel'sConvertEmptyStringsToNullturns that intonullbefore it reaches validation, soProfileController::update()saved a null into a NOT NULL column:Hence the 500, the picture never being removed, and no message reaching the user. Reproduced directly against the column before fixing.
The old guard
if ($user->wasChanged('avatar') && $user->avatar)also skipped the clear case, so even without the constraint erroravatar_media_idwould have stayed pointing at media that no longer represented the user, which is the part the issue's suggested fix covers.Change
avatar.pngin this schema, never null, which is the conventionAuthApiControllerandBackfillMediaAttachmentsalready follow.avatar_media_id.avatarentirely still leaves the existing picture alone, sincevalidated()only returns keys the request actually sent.User::DEFAULT_AVATARalongside ahasCustomAvatar()helper, so the magic string is not spread further.Tests
New
tests/Feature/ProfileAvatarTest.php, 4 tests / 13 assertions, all passing:They live in their own file rather than in
ProfileTestbecauseProfileTestis red onmainfor an unrelated reason: it usesRefreshDatabasewith factory users that carry no permissions, so every request 403s onProfileUpdateRequest::authorize()'sedit-profilecheck. These follow theDatabaseTransactions+ explicit permission grant pattern thatUserCreationTestuses and that does pass. Worth a separate issue.npx tsc --noEmitis clean.