Commit Graph
2 Commits
Author SHA1 Message Date
m038andClaude Opus 4.8 361a6b4d67 fix(review): harden photo reorder against data loss + failure-path drift
Addresses ce-code-review findings on the photo-editor media-API work:

- P0 (#1): PhotoRenumberer now renumbers EVERY on-disk image, using the
  client manifest only as preferred ORDER and appending any omitted image
  at the end. A stale/incomplete `order` (e.g. a second browser tab)
  previously left an unlisted photo at a target slot for phase-2's
  rename() to silently overwrite — verified data loss, now impossible.
  The reorder route inherits the guard; create/reconcile is unchanged.
- P2 (#3): unique per-call token in the .reorder-tmp-* name so two
  concurrent renumbers on one folder can't collide and clobber bytes.
- P3 (#7): de-duplicate the manifest so a repeated name can't shift/drop
  a photo.
- P2 (#2): applyReorder + doDelete split the two failure stages — a failed
  refresh AFTER a committed reorder/delete no longer reverts to a stale or
  ghost state, it reconciles to disk. A DELETE 404 is treated as success
  so a retried ghost cell converges.
- P2 (#4): both custom routes call requirePermission('api.pages.write')
  so the GHSA-x7hm API-key scope cap applies (owner already holds it, so
  the owner-only behaviour is unchanged).
- P3 (#8): refresh stale comments (photo-01..NN; drop editLoadPhotos ref).

PhotoRenumberer's 7-case unit suite still passes and the data-loss repro
now preserves all bytes. Assets rebuilt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 20:14:41 +02:00
m038andClaude Opus 4.8 fcf52a0e44 refactor(photos): extract shared zero-padded PhotoRenumberer helper
Factor cache-on-save's renumberPhotos into a shared PhotoRenumberer class
(Grav\Plugin\Shared), the single owner of the photo-NN naming invariant used
by both the create/edit reconcile and the upcoming live reorder route, so their
numbering can't diverge.

Changes vs the old private method:
- Zero-pads to photo-01..NN (pad width grows with the set) so lexicographic
  media order equals numeric order past 9 photos — cover = images|first stays
  correct for 10+ photos. Normalises pre-existing un-padded photo-N on first pass.
- Image-extension guard moved into the helper: only real image files on disk are
  renamed, so a crafted manifest naming the entry .md, a .gpx or a .meta.yaml is
  skipped by every caller, not just cache-on-save.

Create-mode entries now also emit photo-01..NN — an intentional, accepted side
effect of sharing one helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 18:56:59 +02:00