Add Instructors admin page (create + per-capability access) #30

Merged
thatguygriff merged 1 commits from feature/instructor-management into main 2026-06-08 20:05:33 +00:00
Owner

Completes the second half of #9instructor management. The capability slice (the us_studio_admin role and the cap matrix) shipped in #10; this adds the Instructors admin page the issue specifies.

What changed

  • InstructorController (gated on manage_instructors): lists instructors, creates a us_instructor WordPress user (emailing them a set-password link via wp_new_user_notification), and a per-instructor capability detail view.
  • InstructorCapabilities — the pure, unit-tested rules: which managed capabilities the acting admin may assign, and how a submitted form maps to per-user grants/denials. Kept free of WordPress so it's testable (mirrors how StudentController pairs with StudentSchedule).
  • AdminMenu registers the page in the "people" section, and that section's separator now accounts for manage_instructors.
  • Templates instructors.php (list + create form) and instructor-detail.php (capability toggles).

Capability model

The managed (toggleable) capabilities are manage_offerings, manage_questions, view_own_payments, and export_payments. manage_availability and view_own_lessons are core to every instructor and aren't managed here. The us_instructor role grants the managed caps by default; the page layers per-user overrides on top (no change to RoleManager, matching the capability matrix).

A studio admin can never grant a capability it does not itself hold:

  • only caps the acting user holds are offered as toggles — checked via current_user_can(), so an administrator's dynamic studio grant counts;
  • on creation, any managed cap the admin lacks is explicitly denied on the new instructor, so a new account can never exceed its creator.

Checks

composer test (189 tests, 541 assertions), composer lint (PHPStan L6 — no errors), composer cs (PHPCS) all green. New InstructorCapabilitiesTest; docs/features/user-roles.md updated.

Closes #9.

🤖 Generated with Claude Code

Completes the second half of #9 — **instructor management**. The capability slice (the `us_studio_admin` role and the cap matrix) shipped in #10; this adds the **Instructors** admin page the issue specifies. ## What changed - **`InstructorController`** (gated on `manage_instructors`): lists instructors, creates a `us_instructor` WordPress user (emailing them a set-password link via `wp_new_user_notification`), and a per-instructor capability detail view. - **`InstructorCapabilities`** — the pure, unit-tested rules: which managed capabilities the acting admin may assign, and how a submitted form maps to per-user grants/denials. Kept free of WordPress so it's testable (mirrors how `StudentController` pairs with `StudentSchedule`). - **AdminMenu** registers the page in the "people" section, and that section's separator now accounts for `manage_instructors`. - Templates `instructors.php` (list + create form) and `instructor-detail.php` (capability toggles). ## Capability model The managed (toggleable) capabilities are `manage_offerings`, `manage_questions`, `view_own_payments`, and `export_payments`. `manage_availability` and `view_own_lessons` are core to every instructor and aren't managed here. The `us_instructor` role grants the managed caps by default; the page layers **per-user overrides** on top (no change to `RoleManager`, matching the capability matrix). **A studio admin can never grant a capability it does not itself hold:** - only caps the acting user holds are offered as toggles — checked via `current_user_can()`, so an administrator's dynamic studio grant counts; - on creation, any managed cap the admin lacks is explicitly denied on the new instructor, so a new account can never exceed its creator. ## Checks `composer test` (189 tests, 541 assertions), `composer lint` (PHPStan L6 — no errors), `composer cs` (PHPCS) all green. New `InstructorCapabilitiesTest`; `docs/features/user-roles.md` updated. Closes #9. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
thatguygriff added 1 commit 2026-06-08 20:03:04 +00:00
Add Instructors admin page (create + per-capability access)
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 48s
CI / Tests (PHP 8.2) (pull_request) Successful in 49s
CI / Tests (PHP 8.1) (pull_request) Successful in 54s
CI / Coding Standards (pull_request) Successful in 1m5s
CI / PHPStan (pull_request) Successful in 1m11s
CI / Build Plugin Zip (pull_request) Has been skipped
b5c076c3d6
Completes the instructor-management half of #9: the studio admin can now
create instructor accounts and toggle each instructor's capabilities.

- InstructorController (manage_instructors): list instructors, create a
  us_instructor WP user (emailing a set-password link), and a per-instructor
  capability detail view.
- InstructorCapabilities: pure, unit-tested rules for which managed caps an
  admin may assign and how a submitted form maps to assignments. Managed caps
  are manage_offerings, manage_questions, view_own_payments, export_payments;
  manage_availability and view_own_lessons are core to every instructor.
- A studio admin can never grant a capability it does not itself hold: only
  held caps (checked via current_user_can, so an administrator's dynamic grant
  counts) are offered, and on creation any managed cap the admin lacks is
  denied on the new instructor so they never exceed their creator. The role
  grants the managed caps by default; the page layers per-user overrides.
- AdminMenu: register the Instructors page in the people section.
- Tests for the capability logic; docs/features/user-roles.md updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
thatguygriff merged commit fe43f91fb1 into main 2026-06-08 20:05:33 +00:00
thatguygriff deleted branch feature/instructor-management 2026-06-08 20:05:33 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Unsupervised/unsupervised-scheduler#30