Admin: preview, crop & shuffle the Star Wars easter-egg figure in the Person cropper (#1304) - #1306
Merged
Merged
Conversation
…opper (#1304) A new Person has no easter_egg image, so the Cropper.js widget was blank and Person.save() assigned a random Star Wars figure invisibly — no way to preview, re-roll, or crop it up front. This wires a figure picker into the easter-egg cropper: - New EasterEggCropImageWidget (CropImageWidget subclass) embeds the figure list as JSON and renders an accessible "Shuffle" button. - ml_cropper.js seeds a random figure on an empty field (new Person), reveals Shuffle on every Person (so an existing easter egg can be swapped too), and clears the choice when the editor uploads their own image (upload wins). - PersonAdminForm copies the chosen figure into easter_egg on save when the editor shuffled and didn't upload; the hidden choice field is validated against the known figure list (guards path traversal). The crop box persists via the existing easter_egg_crop ratio field. - Person.save()'s random fallback is unchanged for the untouched/non-admin path. - fileutils.list_starwars_images() is the single source of truth; the random picker now draws from it. Tests: website/tests/test_easter_egg_picker.py covers all three save paths (chosen / shuffled-on-existing / uploaded), the random fallback, untouched-edit preservation, and the path-traversal rejection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Closes #1304.
What & why
A brand-new
Personhas noeaster_eggimage, so the Cropper.js widget was blank on load andPerson.save()assigned a random Star Wars LEGO figure invisibly — no way to preview, re-roll, or crop it up front. This wires a figure picker into the easter-egg cropper.Behavior
How it works
EasterEggCropImageWidget(aCropImageWidgetsubclass) embeds the figure list as JSON and renders an accessible<button type="button">Shuffle control.ml_cropper.jsseeds a default on an empty field, reveals Shuffle on every Person, records the chosen figure's basename in a hiddeneaster_egg_starwars_choicefield, and clears it on upload.PersonAdminFormvalidates the choice against the known figure list (guards path traversal) and copies that figure intoeaster_eggon save when the editor shuffled and didn't upload.fileutils.list_starwars_images()is the single source of truth; the random picker now draws from it.ImageRatioField/crop_corners/ easy_thumbnails are unchanged.Design questions (from the issue)
fileutils.list_starwars_images(), embedded in the widget (no new endpoint).Person.save()random fallback retained for non-admin/bulk.easter_egg;easter_egg_cropholds the box.easter_eggonly (headshotimagekeeps the plain crop widget).Tests
website/tests/test_easter_egg_picker.py(10 tests) covers the three save paths (chosen / shuffled-on-existing / uploaded), the random fallback, untouched-edit preservation, and path-traversal rejection. Full suite: 159 passing.Screenshots
Here's the UI:
A11y
Shuffle is a semantic
<button>; the existing keyboard-accessible numeric crop controls are unchanged. Run the Pa11y profile before merge.🤖 Generated with Claude Code