Commit Graph

4 Commits

Author SHA1 Message Date
thatguygriff f3f5c7801f Security fixes: CSV injection, policy body output, invite hashing, slot datetimes
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.1) (pull_request) Successful in 43s
CI / Tests (PHP 8.3) (pull_request) Successful in 49s
CI / Tests (PHP 8.2) (pull_request) Successful in 59s
CI / Coding Standards (pull_request) Successful in 1m11s
CI / PHPStan (pull_request) Successful in 1m20s
CI / Build Plugin Zip (pull_request) Has been skipped
Four fixes from a security review pass:

- Neutralise CSV formula injection in the payments export: fields with a
  leading =, +, -, @, tab, or CR (e.g. a hostile student display name) are
  apostrophe-prefixed in PaymentReport::csvLine() so they open as text in
  Excel/Google Sheets. Fixes #39.
- Sanitise policy bodies with wp_kses_post at output in
  PolicyEndpoint::index() (the booking JS renders that HTML raw), so a
  future write path that forgets kses can never become stored XSS.
  Fixes #40.
- Store invite tokens hashed (SHA-256) at rest: a database leak can no
  longer redeem pending invites. The registration link is shown once, at
  creation; the pending list shows email/invited date; lookups hash the
  submitted token. Existing plaintext pending invites must be re-issued.
  Fixes #41.
- Validate availability slot datetimes on both creation paths (REST and
  admin form) via AvailabilitySlot::normalizeDateTime(): canonical and
  datetime-local forms normalise to Y-m-d H:i:s, garbage and end <= start
  are rejected (REST 400) instead of reaching the DATETIME column or
  throwing inside the weekly-series date arithmetic. Fixes #42.

composer test (204 tests, 594 assertions), PHPStan L6, and PHPCS all green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 16:36:26 -03:00
thatguygriff 9cb5207dcd Add group-class enrolment (year commitment, capacity, registration gate)
CI / Tests (PHP 8.1) (pull_request) Successful in 45s
CI / Coding Standards (pull_request) Successful in 50s
CI / PHPStan (pull_request) Successful in 1m4s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.2) (pull_request) Successful in 42s
CI / Tests (PHP 8.3) (pull_request) Successful in 42s
CI / Build Plugin Zip (pull_request) Has been skipped
Implements #4: students enrol in a group_class offering via the same
registration gate as private lessons (intake questions + booking-scoped
policy acceptance). Enrolment is capacity-enforced and prevents duplicates.

- Schema: us_group_enrollments table.
- Enrollment value object + EnrollmentRepository (countActiveForOffering,
  hasActiveEnrollment, per-student/instructor/all-active queries, status).
- EnrollmentEndpoint: GET /enrollments (scoped) and POST /enrollments
  (validates group_class, capacity, no-duplicate; reuses RegistrationGate;
  records answers/acceptances type enrollment).
- GroupClassController + admin page (view_all_lessons): all active enrolments.
- Front-end: [us_group_classes] shortcode (GroupClassPage) + group-classes.js
  enrol flow (list classes -> questions + policies -> POST /enrollments).
- Wiring in Plugin, RestRegistrar, AdminMenu, ShortcodeRegistrar.

Payment is the deferred seam (#7): enrolment lands active, payment_id null.
JS left untested for parity with the repo's no-build vanilla-JS posture.

Tests: tests/Unit/GroupClass/ (Enrollment, EnrollmentRepository).
composer test (121), cs, and PHPStan level 6 all pass.

Refs #4

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 11:43:33 -03:00
thatguygriff 9c900d6553 Add account registration with signup policy acceptance
CI / Tests (PHP 8.1) (pull_request) Successful in 47s
CI / No Debug Code (pull_request) Successful in 2s
CI / Build Plugin Zip (pull_request) Has been skipped
CI / Coding Standards (pull_request) Successful in 52s
CI / PHPStan (pull_request) Successful in 1m1s
CI / Tests (PHP 8.2) (pull_request) Successful in 48s
CI / Tests (PHP 8.3) (pull_request) Successful in 45s
Implements #16: invite-only student self-registration through a front-end
page, accepting signup-scoped policies at account creation.

Policy domain:
- us_policies.acceptance_scope (signup/booking/both); Policy::appliesTo();
  PolicyRepository::findForScope(); scope threaded through PolicyService,
  the REST create, the admin controller, and the Policies form.
- PolicyAcceptance::REG_ACCOUNT (registration_id = the new user's ID).

Auth:
- Invite value object + InviteRepository; us_invites table.
- RegistrationController + Invites admin page (manage_students): invite an
  email, share the registration link, revoke.
- RegistrationPage ([us_student_register] shortcode): validates the invite
  token, collects name/password, renders signup-scoped published policies
  with required acceptance, creates the us_student user, records account-type
  acceptances, marks the invite accepted, and logs the user in.
- RoleManager: manage_students cap added to STUDIO_ADMIN_CAPS.

Invite-only is implemented; the us_registration_mode self_approval path is a
documented future seam.

Docs: docs/features/account-registration.md; policies.md updated.
Tests: tests/Unit/Auth/ (Invite, InviteRepository) plus Policy scope
updates. composer test (104), cs, and PHPStan level 6 all pass.

Refs #16

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 16:39:39 -03:00
thatguygriff 0fbafc9d18 Initial plugin scaffold: lesson scheduling WordPress plugin
CI / Coding Standards (push) Failing after 2m31s
CI / PHPStan (push) Failing after 50s
CI / Tests (PHP 8.1) (push) Successful in 50s
CI / Tests (PHP 8.2) (push) Successful in 48s
CI / Tests (PHP 8.3) (push) Successful in 40s
CI / No Debug Code (push) Successful in 2s
- Custom DB tables for availability slots and lesson bookings
- Instructor (wp-admin) and student (front-end) roles with custom capabilities
- REST API under us-scheduler/v1 for availability CRUD and booking
- [us_booking] and [us_student_login] shortcodes for student front end
- PHPUnit + Brain\Monkey unit test suite (29 tests)
- Gitea Actions CI: lint, PHPStan, tests on PHP 8.1/8.2/8.3, no-debug check
- Feature docs under docs/features/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 12:44:46 -03:00