Skip to content

Phase 14c-2: editor pages module on iManager 2.0#24

Merged
bigin merged 1 commit into
imanager-2.0from
phase-14c2-pages
May 3, 2026
Merged

Phase 14c-2: editor pages module on iManager 2.0#24
bigin merged 1 commit into
imanager-2.0from
phase-14c2-pages

Conversation

@bigin
Copy link
Copy Markdown
Owner

@bigin bigin commented May 3, 2026

Summary

The /editor/pages admin module is back online — list, create, edit,
save, delete, drag-renumber and Markdown preview, all on the iManager
2.0 stack with Csrf + Sanitizer + Request + Frontend\PageRepository.

Frontend\PageRepository write surface added (still final readonly):

  • save(Item) — persist via ItemRepository, wrap as Page
  • delete(int) — idempotent forward
  • renumber(list<int>) — bulk position rewrite by id-order
  • slugTaken(slug, parent) — uniqueness preflight, scoped to parent
  • nextPosition() — helper for new-page position default

New Editor\Pages\PagesModule covers the legacy 612-line
editor/modules/pages/pages.php:

  • renderList: sortable table with edit/delete actions, CSRF token
    for inline form (renumber + delete links).
  • renderEdit: name/menu_title/slug/content/parent/template/published
    fields. Image section is read-only for 14c-2 (existing entries
    listed; upload widget reattaches in 14d with FilePond + UploadHandler).
  • saveAction: validates name+slug+content, derives slug from name
    when omitted, rejects reserved slugs, rejects duplicate slug under the
    same parent, preserves existing image data on update; flashes success
    and redirects to /pages/edit/?page=N.
  • deleteAction: refuses page id=1, refuses pages with children,
    flashes success/error and redirects to /pages/.
  • renumberAction: AJAX endpoint returning {status:0|1}; CSRF-checked.
  • markdownPreviewAction: AJAX endpoint returning {status:1, text:HTML}
    rendered via Sanitizer::markdown().

EditorRouter routes /editor/pages* to PagesModule and removes the
"coming soon" placeholder for that slug; auth gating still kicks anonymous
GET/POST to /editor/auth/ before reaching the module.

CSRF: all write paths check tokens via Imanager\Http\Csrf — login
form, edit/save form, delete link, renumber AJAX, markdown preview.
Tokens are scoped per-form-name ("pages" for the module's form).

Test plan

  • GET /editor/pages 200, sortable table, 8 migrated rows
  • GET /editor/pages/edit/?page=3 200, edit form pre-filled
  • GET /editor/pages/edit/ 200, empty new-page form
  • POST save (new) 302 → /pages/edit/?page=10 (DB row +1)
  • POST render-markdown 200 JSON {status:1, text:...}
  • GET /pages/delete/?page=10&… 302 → /pages/ (DB row gone)
  • Anonymous GET /editor/pages 302 → /editor/auth/
  • Anonymous POST /editor/pages 302 → /editor/auth/
  • Browser smoke against ServBay (drag-sort UX)

The /editor/pages admin module is back online — list, create, edit,
save, delete, drag-renumber and Markdown preview, all on the iManager
2.0 stack with Csrf + Sanitizer + Request + Frontend\PageRepository.

Frontend\PageRepository write surface added (still final readonly):
  - save(Item)               persist via ItemRepository, wrap as Page
  - delete(int)              idempotent forward
  - renumber(list<int>)      bulk position rewrite by id-order
  - slugTaken(slug, parent)  uniqueness preflight, scoped to parent
  - nextPosition()           helper for new-page position default

New Editor\Pages\PagesModule covers the legacy 612-line
editor/modules/pages/pages.php:
  - renderList: sortable table with edit/delete actions, CSRF token
    for inline form (renumber + delete links).
  - renderEdit: name/menu_title/slug/content/parent/template/published
    fields. Image section is read-only for 14c-2 (existing entries
    listed; upload widget reattaches in 14d with FilePond +
    UploadHandler).
  - saveAction: validates name+slug+content, derives slug from name
    when omitted, rejects reserved slugs, rejects duplicate slug under
    the same parent, preserves existing image data on update; flashes
    success and redirects to /pages/edit/?page=N.
  - deleteAction: refuses page id=1, refuses pages with children,
    flashes success/error and redirects to /pages/.
  - renumberAction: AJAX endpoint returning {status:0|1}; CSRF-checked.
  - markdownPreviewAction: AJAX endpoint returning {status:1, text:HTML}
    rendered via Sanitizer::markdown().

EditorRouter routes /editor/pages* to PagesModule and removes the
"coming soon" placeholder for that slug; auth gating still kicks
anonymous GET/POST to /editor/auth/ before reaching the module.

CSRF: all write paths check tokens via Imanager\Http\Csrf — login
form, edit/save form, delete link, renumber AJAX, markdown preview.
Tokens are scoped per-form-name ("pages" for the module's form).

Manual smoke (PHP built-in server):
  GET  /editor/pages              200, sortable table, 8 migrated rows
  GET  /editor/pages/edit/?page=3 200, edit form pre-filled (Get started)
  GET  /editor/pages/edit/        200, empty new-page form
  POST save (new)                 302 → /pages/edit/?page=10 (DB row +1)
  POST render-markdown            200 JSON {status:1, text:...}
  GET  /pages/delete/?page=10&...  302 → /pages/ (DB row gone)
  Anonymous GET /editor/pages      302 → /editor/auth/
  Anonymous POST /editor/pages     302 → /editor/auth/
@bigin bigin merged commit f3ce77b into imanager-2.0 May 3, 2026
@bigin bigin deleted the phase-14c2-pages branch May 15, 2026 05:24
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.

1 participant