694366a6c88cc408b37c09b2ee19af535b51d74a
295
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
694366a6c8
|
Merge pull request 'Add editable, previewable payment-due email template' (#203) from feature/editable-payment-due-email into main
CI / Coding Standards (push) Successful in 15s
CI / No Debug Code (push) Successful in 4s
CI / Tests (PHP 8.5) (push) Successful in 23s
CI / Tests (PHP 8.2) (push) Successful in 29s
CI / Tests (PHP 8.1) (push) Successful in 52s
CI / Tests (PHP 8.3) (push) Successful in 52s
CI / Static Analysis (push) Successful in 1m2s
CI / Build Plugin Zip (push) Successful in 12s
Release / Build and Publish Release (push) Successful in 22s
Release / Open next-version bump PR (push) Successful in 4s
Reviewed-on: #203 Reviewed-by: James Griffin-Allwood <[email protected]>v1.6.0 |
||
|
|
a2c609803e
|
Add editable, previewable payment-due email template
CI / Coding Standards (pull_request) Successful in 29s
CI / Tests (PHP 8.2) (pull_request) Successful in 31s
CI / Tests (PHP 8.3) (pull_request) Successful in 31s
CI / Tests (PHP 8.5) (pull_request) Successful in 31s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.1) (pull_request) Successful in 44s
CI / Static Analysis (pull_request) Successful in 51s
CI / Build Plugin Zip (pull_request) Skipped
The "Payment due" notice the daily billing scan sends was fixed wording
baked into PaymentDueMailer. Studio admins can now view, edit and preview
its subject and body under Studio Settings -> Payment Due Email.
- PaymentDueEmailTemplate stores subject/body/item-line as us_payment_due_email_*
options, each falling back to the built-in default when blank, and renders
via {token} substitution.
- PaymentDueMailer now builds a token map from the same consolidated
items/credit/e-transfer/reference data and renders the stored template; the
default template reproduces the previous wording exactly.
- PaymentEmailController serves the view/edit/save/reset admin page
(manage_billing, nonce-checked) with a server-rendered sample preview.
- PaymentEmailPreviewEndpoint (POST us-scheduler/v1/payment-email/preview,
manage_billing) + payment-email-admin.js drive a live preview of unsaved edits.
- Submenu wired under Studio Settings; endpoint wired in RestRegistrar.
- Bump to 1.6.0 and add CHANGELOG entry. New options default gracefully, so
existing sites need no migration and send the identical notice until edited.
Co-authored-by: anthropic/claude-opus-4-8
|
||
|
|
ad4e4ae357
|
Merge pull request 'Apply account credit on same-month rebook; show total credit on student page' (#202) from feature/student-credit-display-and-rebook-fix into main
CI / Coding Standards (push) Successful in 28s
CI / Tests (PHP 8.2) (push) Successful in 31s
CI / Tests (PHP 8.5) (push) Successful in 32s
CI / No Debug Code (push) Successful in 9s
CI / Static Analysis (push) Successful in 37s
CI / Tests (PHP 8.1) (push) Successful in 44s
CI / Tests (PHP 8.3) (push) Successful in 44s
CI / Build Plugin Zip (push) Successful in 13s
Reviewed-on: #202 Reviewed-by: James Griffin-Allwood <[email protected]> |
||
|
|
1a166eb4e3
|
Add changelog entries for the credit fix and student-page display
CI / Coding Standards (pull_request) Successful in 30s
CI / Tests (PHP 8.2) (pull_request) Successful in 33s
CI / Tests (PHP 8.5) (pull_request) Successful in 33s
CI / Static Analysis (pull_request) Successful in 38s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.1) (pull_request) Successful in 42s
CI / Tests (PHP 8.3) (pull_request) Successful in 41s
CI / Build Plugin Zip (pull_request) Skipped
Recorded under the current 1.5.8 section; no version bump. Co-authored-by: anthropic/claude-opus-4-8 |
||
|
|
362980d008
|
Apply available credit to any at-booking charge, not just scheduled
CI / Coding Standards (pull_request) Successful in 31s
CI / Tests (PHP 8.2) (pull_request) Successful in 30s
CI / Tests (PHP 8.3) (pull_request) Successful in 31s
CI / No Debug Code (pull_request) Successful in 5s
CI / Tests (PHP 8.1) (pull_request) Successful in 43s
CI / Tests (PHP 8.5) (pull_request) Successful in 42s
CI / Static Analysis (pull_request) Successful in 56s
CI / Build Plugin Zip (pull_request) Skipped
A payer's account credit should offset any charge raised at booking, so drop the scheduled-only guard. Covers the one-time pay-now flow too. Co-authored-by: anthropic/claude-opus-4-8 |
||
|
|
e3ab7973d6
|
Clarify credit-at-booking comment scopes to scheduled charges
CI / Coding Standards (pull_request) Successful in 30s
CI / Tests (PHP 8.2) (pull_request) Successful in 32s
CI / Tests (PHP 8.3) (pull_request) Successful in 37s
CI / Static Analysis (pull_request) Successful in 38s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.1) (pull_request) Successful in 46s
CI / Tests (PHP 8.5) (pull_request) Successful in 45s
CI / Build Plugin Zip (pull_request) Skipped
Co-authored-by: anthropic/claude-opus-4-8 |
||
|
|
1758c253a1
|
Trim credit-at-booking comment to one line
CI / Coding Standards (pull_request) Successful in 23s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.2) (pull_request) Successful in 33s
CI / Tests (PHP 8.5) (pull_request) Successful in 34s
CI / Static Analysis (pull_request) Successful in 39s
CI / Tests (PHP 8.3) (pull_request) Successful in 38s
CI / Tests (PHP 8.1) (pull_request) Successful in 46s
CI / Build Plugin Zip (pull_request) Skipped
Co-authored-by: anthropic/claude-opus-4-8 |
||
|
|
67017409d7
|
Drop stale comment about not applying credit at booking
CI / Coding Standards (pull_request) Successful in 29s
CI / Tests (PHP 8.1) (pull_request) Successful in 36s
CI / No Debug Code (pull_request) Successful in 11s
CI / Tests (PHP 8.5) (pull_request) Successful in 36s
CI / Static Analysis (pull_request) Successful in 41s
CI / Tests (PHP 8.2) (pull_request) Successful in 43s
CI / Tests (PHP 8.3) (pull_request) Successful in 43s
CI / Build Plugin Zip (pull_request) Skipped
This change applies credit at booking for scheduled rebooks, so the note saying the pay-now flow deliberately does not was contradictory. Co-authored-by: anthropic/claude-opus-4-8 |
||
|
|
e7de627752
|
Apply account credit on same-month rebook, surface credit on student page
CI / Coding Standards (pull_request) Successful in 27s
CI / Tests (PHP 8.2) (pull_request) Successful in 28s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.5) (pull_request) Successful in 35s
CI / Tests (PHP 8.1) (pull_request) Successful in 37s
CI / Tests (PHP 8.3) (pull_request) Successful in 43s
CI / Static Analysis (pull_request) Successful in 51s
CI / Build Plugin Zip (pull_request) Skipped
A monthly/weekly lesson booked into a month whose billing date has already passed is charged at booking time by LessonBooker::settle, bypassing the daily scan where account credit is otherwise applied. So rebooking a cancelled paid lesson within the same month charged the family in full while their cancellation credit sat unused — billed twice for the same slot. Apply the payer's credit to that charge-at-booking payment for scheduled offerings, mirroring the daily scan: a payment fully covered by credit settles and confirms its lesson. Add PaymentService::findPayment so settle can re-read the row after applyCredits writes to it. Also surface the student's total account credit at the top of their detail page when they hold a balance, so the studio sees it at a glance. Co-authored-by: anthropic/claude-opus-4-8 |
||
|
|
d8d842b1ef
|
Merge pull request 'Fix two duplicate-charge bugs in scheduled billing' (#201) from fix/duplicate-payment-due-notice into main
CI / Coding Standards (push) Successful in 16s
CI / No Debug Code (push) Successful in 5s
CI / Tests (PHP 8.5) (push) Successful in 24s
CI / Tests (PHP 8.1) (push) Successful in 40s
CI / Tests (PHP 8.3) (push) Successful in 46s
CI / Static Analysis (push) Successful in 1m2s
CI / Tests (PHP 8.2) (push) Successful in 1m1s
CI / Build Plugin Zip (push) Successful in 15s
Reviewed-on: #201 Reviewed-by: James Griffin-Allwood <[email protected]> |
||
|
|
acda3cda0f
|
Reconcile up-front charges when a class switches to monthly billing
CI / Coding Standards (pull_request) Successful in 25s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.1) (pull_request) Successful in 36s
CI / Tests (PHP 8.2) (pull_request) Successful in 39s
CI / Tests (PHP 8.3) (pull_request) Successful in 51s
CI / Tests (PHP 8.5) (pull_request) Successful in 59s
CI / Static Analysis (pull_request) Successful in 1m3s
CI / Build Plugin Zip (pull_request) Skipped
A student who enrols while a group class is pay-now is charged once at enrolment, and that charge carries no period_key. When the class is later switched to monthly, the daily scan — which dedups scheduled charges by period_key — does not see the up-front charge and bills the enrolment again for the current month, double-charging students who had already paid. The differing payer between the two rows (student vs guardian) was a side effect of guardian links created between the two charge dates, not the cause. Switching a group class into monthly now adopts each active enrolment's up-front charge into the current month (stamping period_key and due_date) so the scan treats that month as billed and charges from the next month on. Enrolments with no up-front charge, or already billed for the month, are left alone; weekly and non-group offerings are not touched. Wired into both offering-update paths (admin form and REST). Co-authored-by: anthropic/claude-opus-4-8 |
||
|
|
e389e40843
|
Send each scheduled payment's due notice exactly once
CI / Coding Standards (pull_request) Successful in 28s
CI / Tests (PHP 8.1) (pull_request) Successful in 35s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.3) (pull_request) Successful in 44s
CI / Tests (PHP 8.2) (pull_request) Successful in 47s
CI / Tests (PHP 8.5) (pull_request) Successful in 48s
CI / Static Analysis (pull_request) Successful in 52s
CI / Build Plugin Zip (pull_request) Skipped
The daily billing scan runs on request via WP-Cron and can overlap itself under concurrent traffic. Each run emailed the payments it created with no record that a notice had gone out, so two overlapping runs could send a payer two identical "Payment due" emails for one charge — read by families as being billed twice, though only one row exists. Stamp us_payments.notice_sent_at atomically before emailing: the scan now claims each payment with a conditional UPDATE ... WHERE notice_sent_at IS NULL and only notices, credits and batches the rows it won. A competing run finds them claimed and stays quiet, so exactly one notice is sent regardless of how the scan is triggered. A one-time backfill stamps existing scheduled rows on upgrade so already-noticed charges are not re-emailed. Co-authored-by: anthropic/claude-opus-4-8 |
||
|
|
6c92fc35fd
|
Delete directory '.claude'
CI / Coding Standards (push) Successful in 17s
CI / No Debug Code (push) Successful in 5s
CI / Tests (PHP 8.5) (push) Successful in 24s
CI / Tests (PHP 8.2) (push) Successful in 35s
CI / Tests (PHP 8.1) (push) Successful in 51s
CI / Tests (PHP 8.3) (push) Successful in 52s
CI / Static Analysis (push) Successful in 1m2s
CI / Build Plugin Zip (push) Successful in 16s
|
||
|
|
cd86f6bdeb
|
Merge pull request 'Add AGENTS.md, point CLAUDE.md files at it' (#200) from docs/agent-instructions into main
CI / Coding Standards (push) Successful in 24s
CI / No Debug Code (push) Successful in 8s
CI / Tests (PHP 8.5) (push) Successful in 33s
CI / Static Analysis (push) Successful in 38s
CI / Tests (PHP 8.2) (push) Successful in 36s
CI / Tests (PHP 8.1) (push) Successful in 47s
CI / Tests (PHP 8.3) (push) Successful in 47s
CI / Build Plugin Zip (push) Successful in 12s
Reviewed-on: #200 Reviewed-by: James Griffin-Allwood <[email protected]> |
||
|
|
63ee248695
|
Add AGENTS.md, point CLAUDE.md files at it
CI / Coding Standards (pull_request) Successful in 14s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.1) (pull_request) Successful in 34s
CI / Tests (PHP 8.3) (pull_request) Successful in 43s
CI / Tests (PHP 8.5) (pull_request) Successful in 45s
CI / Tests (PHP 8.2) (pull_request) Successful in 1m0s
CI / Static Analysis (pull_request) Successful in 1m2s
CI / Build Plugin Zip (pull_request) Skipped
Co-authored-by: opencode/muse-spark-1.3-contributor-free |
||
|
|
91eb30b222
|
Merge pull request 'Sign the automated version bump commit in CI' (#199) from ci/sign-version-bump-commit into main
CI / Coding Standards (push) Successful in 30s
CI / Tests (PHP 8.5) (push) Successful in 27s
CI / Tests (PHP 8.3) (push) Successful in 34s
CI / No Debug Code (push) Successful in 6s
CI / Static Analysis (push) Successful in 38s
CI / Tests (PHP 8.1) (push) Successful in 41s
CI / Tests (PHP 8.2) (push) Successful in 40s
CI / Build Plugin Zip (push) Successful in 23s
Reviewed-on: #199 Reviewed-by: James Griffin-Allwood <[email protected]> |
||
|
|
c4b2b5ccff
|
Sign the automated version bump commit in CI
CI / Coding Standards (pull_request) Successful in 23s
CI / Tests (PHP 8.5) (pull_request) Successful in 27s
CI / Tests (PHP 8.2) (pull_request) Successful in 35s
CI / Static Analysis (pull_request) Successful in 39s
CI / Tests (PHP 8.3) (pull_request) Successful in 40s
CI / Tests (PHP 8.1) (pull_request) Successful in 49s
CI / No Debug Code (pull_request) Successful in 35s
CI / Build Plugin Zip (pull_request) Skipped
main now requires signed commits, and Gitea refuses to merge a pull request carrying an unsigned one, so the post-release bump PR could not be merged without disabling the protection first. The runner now signs that commit with a dedicated release-bot SSH key held as an organisation Actions secret, trusted by the instance through [repository.signing] TRUSTED_SSH_KEYS. The key Gitea signs merge commits with lives on the server and no runner can reach it. The step fails fast when the secret is missing, unparseable or passphrase protected, and the commit is re-read before pushing so an unsigned one is caught here rather than days later at merge time. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
a4f694a966
|
Merge pull request 'Bump version to 1.5.7' (#198) from release/bump-1.5.7 into main
CI / Coding Standards (push) Successful in 21s
CI / Tests (PHP 8.1) (push) Successful in 30s
CI / Static Analysis (push) Successful in 36s
CI / Tests (PHP 8.2) (push) Successful in 40s
CI / Tests (PHP 8.5) (push) Successful in 25s
CI / Tests (PHP 8.3) (push) Successful in 36s
CI / No Debug Code (push) Successful in 37s
CI / Build Plugin Zip (push) Successful in 22s
Reviewed-on: #198 Reviewed-by: James Griffin-Allwood <[email protected]> |
||
|
|
b9f7c96ce6 | Bump version to 1.5.7 and open changelog section | ||
|
|
f58585be0d
|
Merge pull request 'Fix five findings from a security assessment of the plugin' (#197) from security/assessment-hardening into main
CI / Coding Standards (push) Successful in 18s
CI / No Debug Code (push) Successful in 6s
CI / Tests (PHP 8.5) (push) Successful in 33s
CI / Static Analysis (push) Successful in 37s
CI / Tests (PHP 8.1) (push) Successful in 37s
CI / Tests (PHP 8.3) (push) Successful in 37s
CI / Tests (PHP 8.2) (push) Successful in 39s
CI / Build Plugin Zip (push) Successful in 12s
Release / Build and Publish Release (push) Successful in 25s
Release / Open next-version bump PR (push) Successful in 4s
Reviewed-on: #197 Reviewed-by: James Griffin-Allwood <[email protected]>v1.5.6 |
||
|
|
ae1a62883e
|
Fix the CI failures in the uninstaller work
CI / Coding Standards (pull_request) Successful in 28s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.1) (pull_request) Successful in 38s
CI / Tests (PHP 8.3) (pull_request) Successful in 40s
CI / Tests (PHP 8.2) (pull_request) Successful in 49s
CI / Static Analysis (pull_request) Successful in 1m0s
CI / Tests (PHP 8.5) (pull_request) Successful in 57s
CI / Build Plugin Zip (pull_request) Skipped
Both were mine, and both were in code the earlier commit could not run. The four test failures shared one cause: UninstallerTest stubbed get_option with an arrow function, which captures by value, so every read answered from a snapshot of the options taken at setUp — before the test set any and before the run wrote any. Every assertion that depended on reading back what had just been written therefore saw an empty store. The file's other stubs already use by-reference closures; this one now does too. The phpcs error is WordPress.DB.PreparedSQL.NotPrepared on the table drop. The sniff cannot follow $sql across the null guard that PHPStan requires (prepare() is nullable), and unlike the repositories — which call through a typed $this->db property the sniff does not track at all — the uninstaller calls the global $wpdb, so the sniff sees it. Silenced explicitly, with the reason. composer test (996 tests, 2871 assertions), composer lint and composer cs all pass locally on PHP 8.4. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
1847159e31
|
Fix five findings from a security assessment of the plugin
The assessment looked for three things: whether students can reach each other's bookings, whether payment settings can be dodged, and whether the plugin opens a way into the rest of the install. The student-isolation and payment paths held up. These are what did not. - The front-end login form told WordPress not to work out whether the site was secure, so on HTTPS every student's session cookie was issued without the Secure flag. wp_signon() only derives it from is_ssl() when the second argument is left at its default; an explicit false reads like "no preference" and is not. - The update check took whatever download URL the release API returned and handed it to core, which unpacks it over the installed plugin. The package must now be https on git.unsupervised.ca exactly, compared on the parsed host so a lookalike name cannot pass. - Uninstalling dropped 2 of 14 tables and left the Stripe secret and webhook signing key in wp_options. Removal is now a choice made in advance on Access -> Plugin removal: records are kept unless the owner opts in (with a typed confirmation), while credentials and the borrowed core registration settings go every time. - Open registration switches on the site-wide users_can_register and makes Student the default role, arming any other signup form on the site to mint students who could book and be billed immediately. The pending state is now decided once, on user_register, rather than by whichever form created the account. - Cancel and withdraw answered "not yours" differently from "does not exist", which let a signed-in student enumerate the studio's bookings. Both now give the same 404. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
74df3f5ba8
|
Merge pull request 'Bump version to 1.5.6' (#196) from release/bump-1.5.6 into main
CI / Coding Standards (push) Successful in 25s
CI / No Debug Code (push) Successful in 7s
CI / Tests (PHP 8.5) (push) Successful in 36s
CI / Tests (PHP 8.1) (push) Successful in 44s
CI / Static Analysis (push) Successful in 46s
CI / Tests (PHP 8.2) (push) Successful in 45s
CI / Tests (PHP 8.3) (push) Successful in 49s
CI / Build Plugin Zip (push) Successful in 22s
Reviewed-on: #196 |
||
|
|
f8f211929c | Bump version to 1.5.6 and open changelog section | ||
|
|
61a40f0e8d |
Merge pull request 'Update stripe-php from 17.6.0 to 21.2.1' (#195) from feature/194-stripe-php-21 into main
CI / Coding Standards (push) Successful in 17s
CI / No Debug Code (push) Successful in 1s
CI / Tests (PHP 8.1) (push) Successful in 32s
CI / Tests (PHP 8.5) (push) Successful in 29s
CI / Tests (PHP 8.3) (push) Successful in 42s
CI / Static Analysis (push) Successful in 52s
CI / Tests (PHP 8.2) (push) Successful in 52s
CI / Build Plugin Zip (push) Successful in 23s
Release / Build and Publish Release (push) Successful in 20s
Release / Open next-version bump PR (push) Successful in 4s
Reviewed-on: #195v1.5.5 |
||
|
|
88a8d0ae5c
|
Date the Stripe changelog entry by version rather than by "current"
CI / Coding Standards (pull_request) Successful in 26s
CI / Tests (PHP 8.1) (pull_request) Successful in 28s
CI / No Debug Code (pull_request) Successful in 7s
CI / Tests (PHP 8.2) (pull_request) Successful in 36s
CI / Tests (PHP 8.5) (pull_request) Successful in 34s
CI / Static Analysis (pull_request) Successful in 37s
CI / Tests (PHP 8.3) (pull_request) Successful in 36s
CI / Build Plugin Zip (pull_request) Skipped
"the current Stripe library" is only true until Stripe ships the next major. A changelog is read long after the release it describes, so name the versions — 17 to 21, API version 2026-07-29.dahlia — and let those date the entry. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
e2da45a1b0
|
Update stripe-php from 17.6.0 to 21.2.1
CI / Coding Standards (pull_request) Successful in 27s
CI / No Debug Code (pull_request) Successful in 6s
CI / Tests (PHP 8.1) (pull_request) Successful in 35s
CI / Tests (PHP 8.2) (pull_request) Successful in 34s
CI / Tests (PHP 8.5) (pull_request) Successful in 24s
CI / Tests (PHP 8.3) (pull_request) Successful in 37s
CI / Static Analysis (pull_request) Successful in 45s
CI / Build Plugin Zip (pull_request) Skipped
Four majors behind on the plugin's only production dependency. No site is using Stripe yet and the integration has not been verified end to end, so the pinned API version can move now at close to zero cost — later it would mean coordinating with live payment traffic. The library surface this plugin uses is four symbols, all in StripeGateway: StripeClient, paymentIntents->create, Webhook::constructEvent and Event. Checked each against the installed v21 by reflection; all present with compatible signatures. Most of the breakage flagged across 18 to 21 is in the V2 Events API, which this does not use — webhooks go through the V1 Webhook::constructEvent path. The pinned Stripe API version moves to 2026-07-29.dahlia. Verified beyond the suite, which mocks the client: a real HMAC-signed payload round-trips through Webhook::constructEvent and returns a Stripe\Event with the expected type and data, and a forged signature still raises SignatureVerificationException. The 21.0.0 ErrorObject retyping to null|string produces no new PHPStan findings. Part of #194 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
dfa29745df |
Merge pull request 'Update the dev dependencies' (#193) from chore/update-dev-dependencies into main
CI / Coding Standards (push) Successful in 13s
CI / No Debug Code (push) Successful in 3s
CI / Tests (PHP 8.1) (push) Successful in 30s
CI / Tests (PHP 8.5) (push) Successful in 30s
CI / Tests (PHP 8.2) (push) Successful in 46s
CI / Tests (PHP 8.3) (push) Successful in 45s
CI / Static Analysis (push) Successful in 54s
CI / Build Plugin Zip (push) Successful in 9s
Reviewed-on: #193 |
||
|
|
54a8b906f7
|
Update the dev dependencies
CI / Coding Standards (pull_request) Successful in 20s
CI / No Debug Code (pull_request) Successful in 5s
CI / Static Analysis (pull_request) Successful in 31s
CI / Tests (PHP 8.2) (pull_request) Successful in 31s
CI / Tests (PHP 8.1) (pull_request) Successful in 32s
CI / Tests (PHP 8.3) (pull_request) Successful in 32s
CI / Tests (PHP 8.5) (pull_request) Successful in 35s
CI / Build Plugin Zip (pull_request) Skipped
Routine catch-up on the test and analysis tooling. Every package here is already allowed by the existing constraints, so composer.json does not move and no production dependency is touched. mockery/mockery 1.6.12 -> 1.6.15 phpstan/phpstan 2.2.2 -> 2.2.9 phpunit/phpunit 10.5.63 -> 10.5.64 hamcrest/hamcrest-php v2.1.1 -> v3.0.0 (transitive, via mockery) myclabs/deep-copy 1.13.4 -> 1.14.0 nikic/php-parser v5.7.0 -> v5.8.0 sebastian/recursion-context 5.0.1 -> 5.0.2 Seven patch releases of PHPStan is the one worth watching, since a static analyser routinely gains inferences between them. It reports no new errors here, and PHPCS and the suite are unchanged. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
b3ed3a67d5 |
Merge pull request 'Pin the Composer platform to PHP 8.1 and clear the PHPCS security advisories' (#192) from fix/187-composer-platform-pin into main
CI / Coding Standards (push) Successful in 17s
CI / No Debug Code (push) Successful in 2s
CI / Tests (PHP 8.2) (push) Successful in 32s
CI / Tests (PHP 8.1) (push) Successful in 48s
CI / Static Analysis (push) Successful in 38s
CI / Tests (PHP 8.3) (push) Successful in 47s
CI / Tests (PHP 8.5) (push) Successful in 47s
CI / Build Plugin Zip (push) Successful in 21s
Reviewed-on: #192 |
||
|
|
908b7fcd1f
|
Update the coding-standards tooling off three security advisories
CI / Coding Standards (pull_request) Successful in 16s
CI / No Debug Code (pull_request) Successful in 4s
CI / Tests (PHP 8.3) (pull_request) Successful in 21s
CI / Tests (PHP 8.5) (pull_request) Successful in 22s
CI / Tests (PHP 8.2) (pull_request) Successful in 48s
CI / Tests (PHP 8.1) (pull_request) Successful in 49s
CI / Static Analysis (pull_request) Successful in 57s
CI / Build Plugin Zip (pull_request) Skipped
composer audit reported three advisories against the PHPCS stack, two rated high: squizlabs/php_codesniffer 3.13.5 -> 3.13.6 CVE-2026-67434, OS command injection wp-coding-standards/wpcs 3.3.0 -> 3.4.1 CVE-2026-45293, arbitrary code execution phpcsstandards/phpcsutils 1.2.2 -> 1.2.3 CVE-2026-65954, arbitrary code execution All three are dev-only and none ship in the plugin — bin/build-zip.sh installs --no-dev — but they execute against repository content on every CI run. The existing ^3.7 and ^3.0 constraints already allowed the fixed releases, so composer.json is unchanged. phpcsextra and the codesniffer installer come along as transitive dependencies. Five packages move, none are added or removed, and the updated standards report no new violations. composer audit is now clean. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
b17adf02ff
|
Pin the Composer platform to PHP 8.1
CI / Tests (PHP 8.2) (pull_request) Successful in 26s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 29s
CI / Tests (PHP 8.5) (pull_request) Successful in 30s
CI / Coding Standards (pull_request) Successful in 36s
CI / Tests (PHP 8.1) (pull_request) Successful in 46s
CI / Static Analysis (pull_request) Successful in 49s
CI / Build Plugin Zip (pull_request) Skipped
composer.json declares "php": ">=8.1", but resolution ran against whatever PHP the machine doing the update happened to have. Running composer update on 8.5 could therefore produce a lock containing a package that requires 8.2 or newer, which installs fine locally and fails on the 8.1 leg of the test matrix — a lock that is only discovered to be wrong in CI. config.platform.php makes resolution always target the declared minimum, so a lock that resolves at all is a lock that installs everywhere the plugin claims to run. No package versions change: nothing currently locked requires a PHP newer than 8.1, so this only records platform-overrides and the new content hash. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
a23490ec80 |
Merge pull request 'CI: run jobs in shared ci-php images, commit composer.lock' (#191) from feature/187-run-jobs-in-ci-images into main
CI / Coding Standards (push) Successful in 16s
CI / No Debug Code (push) Successful in 5s
CI / Tests (PHP 8.3) (push) Successful in 25s
CI / Tests (PHP 8.5) (push) Successful in 31s
CI / Static Analysis (push) Successful in 37s
CI / Tests (PHP 8.2) (push) Successful in 35s
CI / Tests (PHP 8.1) (push) Successful in 39s
CI / Build Plugin Zip (push) Successful in 9s
Reviewed-on: #191 |
||
|
|
1552bf4b5f
|
Move the CI image definitions to the shared ci-php repository
CI / Coding Standards (pull_request) Successful in 14s
CI / Tests (PHP 8.1) (pull_request) Successful in 30s
CI / Tests (PHP 8.2) (pull_request) Successful in 30s
CI / Tests (PHP 8.3) (pull_request) Successful in 29s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.5) (pull_request) Successful in 21s
CI / Static Analysis (pull_request) Successful in 37s
CI / Build Plugin Zip (pull_request) Skipped
The image definition and its publishing workflow were only here because this was the first project to need them. They are project-agnostic, so they now live in Unsupervised/ci-php and any PHP project can consume the same tags. The registry path is unchanged — Gitea container images are named owner/image, not after the repository that pushes them — so nothing here needs repointing. Split the combined quality job into separate phpcs and phpstan jobs. They were folded together to halve the number of toolchain installs per run; with the toolchain in the image that saves nothing, and separating them means a coding-standards failure no longer hides the static analysis result. Rewrite the workflow comments to describe what the jobs do rather than the setup step they replaced, and cut docs/ci.md down to what is specific to this project — the image contents and publishing are documented in ci-php. Closes #187 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
f8762e1095
|
Correct the registry auth docs: the Actions token does not work
CI Images / Build CI image (PHP 8.2) (pull_request) Successful in 3s
CI Images / Build CI image (PHP 8.5) (pull_request) Successful in 8s
CI / Tests (PHP 8.3) (pull_request) Successful in 30s
CI Images / Build CI image (PHP 8.3) (pull_request) Successful in 4s
CI / Tests (PHP 8.2) (pull_request) Successful in 23s
CI / Tests (PHP 8.1) (pull_request) Successful in 28s
CI / No Debug Code (pull_request) Successful in 4s
CI / Coding Standards & Static Analysis (pull_request) Successful in 43s
CI / Tests (PHP 8.5) (pull_request) Successful in 23s
CI / Build Plugin Zip (pull_request) Skipped
CI Images / Build CI image (PHP 8.1) (pull_request) Successful in 1m3s
docs/ci.md and the workflow comment both described secrets.GITHUB_TOKEN as the working credential with REGISTRY_TOKEN as a fallback. That is backwards: the task token is rejected by Gitea's container registry (go-gitea/gitea#23642) and the first publish attempt failed on exactly that. REGISTRY_TOKEN is required. Part of #187 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
c9d18fec74
|
Commit composer.lock so CI and releases install a fixed dependency set
CI / Tests (PHP 8.2) (pull_request) Successful in 25s
CI / Tests (PHP 8.1) (pull_request) Successful in 26s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 32s
CI / Coding Standards & Static Analysis (pull_request) Successful in 42s
CI / Tests (PHP 8.5) (pull_request) Successful in 32s
CI / Build Plugin Zip (pull_request) Skipped
composer.lock was gitignored, so `composer install` resolved the graph afresh on every job. CI could quietly start testing different dependency versions than it did the day before, and two builds of the same tag could ship different vendor trees — the run that produces the zip is the same run that picks the versions. Track the lock, and make the two places that consume it use it: - the Composer cache keys hash composer.lock rather than composer.json, since the lock is now what actually fingerprints the dependency set; - bin/build-zip.sh stages the lock alongside composer.json, so the --no-dev production install resolves to the locked versions. It already deleted both from the staging directory before zipping, so the shipped plugin is unchanged. The current lock installs cleanly on 8.1: nothing in it requires a PHP newer than the >=8.1 composer.json declares. Closes #187 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
ab609898d6
|
Run CI and release jobs inside the prebuilt CI images
CI / Coding Standards & Static Analysis (pull_request) Successful in 37s
CI / Tests (PHP 8.1) (pull_request) Successful in 21s
CI / Tests (PHP 8.2) (pull_request) Successful in 20s
CI / Tests (PHP 8.3) (pull_request) Successful in 19s
CI / Tests (PHP 8.5) (pull_request) Successful in 19s
CI / No Debug Code (pull_request) Successful in 2s
CI / Build Plugin Zip (pull_request) Skipped
Replaces setup-php with `container:` in every job that needs PHP. The images published by ci-images.yml already carry PHP, Composer, the intl and zip extensions and the CLI tools the workflow scripts shell out to, so nothing installs PHP at job time any more. That removes the apt path #178 was about: a ~145s floor on 8.3 against ~35s on 8.1/8.2, with a tail that twice ran past the step timeout and failed the run. All three copies of the `Keep downloaded .debs` / `Cache apt packages` workaround go with it. no-debug and bump-version stay on the runner image — neither needs PHP, and no-debug wants the runner's GNU `grep --include`. The Composer cache moves to /composer/cache, which is COMPOSER_HOME in the image, and release.yml gains the cache step it never had. Also corrects the image size in docs/ci.md to the 67MB measured from the published manifest; the ~120MB in the original was an estimate. Closes #187 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
4bc8e80837 |
Merge pull request 'CI: install GNU tar in the CI image so actions/cache works' (#190) from fix/187-ci-image-gnu-tar into main
CI Images / Build CI image (PHP 8.3) (push) Successful in 1m14s
CI Images / Build CI image (PHP 8.2) (push) Successful in 1m30s
CI Images / Build CI image (PHP 8.1) (push) Successful in 1m31s
CI Images / Build CI image (PHP 8.5) (push) Successful in 1m54s
CI / Tests (PHP 8.2) (push) Successful in 52s
CI / No Debug Code (push) Successful in 2s
CI / Tests (PHP 8.5) (push) Successful in 3m0s
CI / Tests (PHP 8.1) (push) Successful in 6m0s
CI / Tests (PHP 8.3) (push) Successful in 6m1s
CI / Coding Standards & Static Analysis (push) Failing after 17m19s
CI / Build Plugin Zip (push) Skipped
Reviewed-on: #190 |
||
|
|
28f586d207
|
Install GNU tar in the CI image so actions/cache works
CI Images / Build CI image (PHP 8.1) (pull_request) Successful in 48s
CI / Tests (PHP 8.1) (pull_request) Successful in 55s
CI Images / Build CI image (PHP 8.2) (pull_request) Successful in 1m46s
CI Images / Build CI image (PHP 8.3) (pull_request) Successful in 1m48s
CI Images / Build CI image (PHP 8.5) (pull_request) Successful in 2m26s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.2) (pull_request) Successful in 53s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m50s
CI / Tests (PHP 8.5) (pull_request) Successful in 2m58s
CI / Coding Standards & Static Analysis (pull_request) Failing after 17m18s
CI / Build Plugin Zip (pull_request) Skipped
actions/cache shells out to `tar --posix -P`. Alpine's busybox tar rejects both flags, so the cache step would fail in every job that runs inside these images — which is all of them once ci.yml switches over. coreutils does not cover this: tar is its own Alpine package. Add it, add zstd (which actions/cache prefers over gzip when present), and assert GNU tar in the image's smoke test so a future base-image change cannot quietly drop it again. Part of #187 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
e097b7a0bf |
Merge pull request 'CI: publish prebuilt CI images to the Gitea container registry' (#188) from feature/187-ci-container-images into main
CI Images / Build CI image (PHP 8.1) (push) Failing after 5s
CI Images / Build CI image (PHP 8.2) (push) Failing after 7s
CI Images / Build CI image (PHP 8.3) (push) Failing after 6s
CI Images / Build CI image (PHP 8.5) (push) Failing after 17s
CI / No Debug Code (push) Successful in 9s
CI / Tests (PHP 8.2) (push) Successful in 52s
CI / Tests (PHP 8.3) (push) Successful in 2m47s
CI / Coding Standards & Static Analysis (push) Successful in 3m41s
CI / Tests (PHP 8.1) (push) Successful in 5m59s
CI / Tests (PHP 8.5) (push) Successful in 7m5s
CI / Build Plugin Zip (push) Successful in 6m0s
Reviewed-on: #188 |
||
|
|
572aaf5b49
|
Publish prebuilt CI images to the Gitea container registry
CI Images / Build CI image (PHP 8.2) (pull_request) Successful in 1m14s
CI Images / Build CI image (PHP 8.1) (pull_request) Successful in 1m26s
CI Images / Build CI image (PHP 8.3) (pull_request) Successful in 2m3s
CI Images / Build CI image (PHP 8.5) (pull_request) Successful in 2m9s
CI / Tests (PHP 8.2) (pull_request) Successful in 1m7s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.3) (pull_request) Successful in 3m8s
CI / Tests (PHP 8.1) (pull_request) Successful in 5m55s
CI / Tests (PHP 8.5) (pull_request) Successful in 6m21s
CI / Coding Standards & Static Analysis (pull_request) Successful in 18m26s
CI / Build Plugin Zip (pull_request) Skipped
setup-php installs PHP 8.3+ from apt on these arm64 runners: a ~145s floor against ~35s for 8.1/8.2, with a tail that twice ran past the step timeout and failed the run (#178). Caching the .debs softened it without removing the apt step, and 8.5 has the same problem. Add a per-version CI image built on php:<version>-cli-alpine and a workflow that publishes it to git.unsupervised.ca/unsupervised/ci-php:<version>. The org is public, so the packages pull anonymously. The image carries bash and nodejs because act_runner runs JavaScript actions inside the job container, GNU coreutils/grep/sed because the workflow scripts use `tac` and `grep --include`, and curl/jq/git/zip for release.yml and bin/build-zip.sh. Composer 2 and the intl and zip extensions round it out. Nothing consumes the images yet — ci.yml and release.yml switch over in a follow-up, because a job cannot run in an image that has not been published. Part of #187 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2 |
||
|
|
116394f2ff |
Merge pull request 'Bump version to 1.5.5' (#189) from release/bump-1.5.5 into main
CI / No Debug Code (push) Successful in 3s
CI / Tests (PHP 8.1) (push) Successful in 53s
CI / Tests (PHP 8.5) (push) Successful in 3m28s
CI / Tests (PHP 8.3) (push) Successful in 5m46s
CI / Tests (PHP 8.2) (push) Successful in 6m14s
CI / Coding Standards & Static Analysis (push) Failing after 12m16s
CI / Build Plugin Zip (push) Skipped
Reviewed-on: #189 |
||
|
|
dda8386c1f | Bump version to 1.5.5 and open changelog section | ||
|
|
7278309bf5 |
Merge pull request 'Let the studio register the students who cannot register themselves' (#186) from fix/185-book-for-child-and-vet-group-enrolment into main
CI / Coding Standards & Static Analysis (push) Successful in 13m23s
CI / Tests (PHP 8.1) (push) Successful in 55s
CI / Tests (PHP 8.2) (push) Successful in 1m7s
CI / Tests (PHP 8.3) (push) Successful in 6m59s
CI / Tests (PHP 8.5) (push) Successful in 12m55s
CI / No Debug Code (push) Successful in 3s
CI / Build Plugin Zip (push) Successful in 5m53s
Release / Build and Publish Release (push) Successful in 8m5s
Release / Open next-version bump PR (push) Successful in 5s
Reviewed-on: #186v1.5.4 |
||
|
|
5ce42f0003
|
Let the studio register the students who cannot register themselves
CI / No Debug Code (pull_request) Successful in 4s
CI / Tests (PHP 8.2) (pull_request) Successful in 50s
CI / Tests (PHP 8.1) (pull_request) Successful in 1m3s
CI / Tests (PHP 8.5) (pull_request) Successful in 2m48s
CI / Tests (PHP 8.3) (pull_request) Successful in 3m24s
CI / Coding Standards & Static Analysis (pull_request) Successful in 8m21s
CI / Build Plugin Zip (pull_request) Skipped
The Book a lesson for a student panel built its picker from the us_student role but vetted the submission with the book_lesson capability. ChildLoginGate and RegistrationLoginGate withhold that capability from accounts that keep the role, so the panel offered every guardian-managed child and every unapproved signup and then refused them — with a message claiming no student had been chosen, and a form cleared of all five fields. Withholding book_lesson stops those accounts registering in their own name. It was never meant to stop the studio acting for them, which is what the panel is for, and for a child is the only route to a lesson besides their guardian. Guard the student role instead, via a new RoleManager::isStudent() shared with every picker and guard on the staff side so the two cannot drift apart again. Group enrolment gets the same predicate: addDirect() and grantAccess() vetted their posted ids not at all, and would enrol an instructor, an administrator, or an account deleted since the page was drawn — raising a real payment against them for a priced class. Keep a refused booking's fields as submitted, reading the form through one LessonController::submittedBooking() so what gets booked and what is shown again cannot disagree about a field name. A booking that succeeds still leaves an empty form, so the next one does not inherit it. Closes #185 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01XunBYk2sFEc1oL14sUiuBU |
||
|
|
76530878b5 |
Merge pull request 'Bump version to 1.5.4' (#184) from release/bump-1.5.4 into main
CI / Tests (PHP 8.1) (push) Successful in 58s
CI / No Debug Code (push) Successful in 2s
CI / Tests (PHP 8.5) (push) Successful in 4m20s
CI / Coding Standards & Static Analysis (push) Successful in 5m21s
CI / Tests (PHP 8.2) (push) Successful in 6m4s
CI / Tests (PHP 8.3) (push) Successful in 12m56s
CI / Build Plugin Zip (push) Successful in 2m39s
Reviewed-on: #184 |
||
|
|
6031a75012 | Bump version to 1.5.4 and open changelog section | ||
|
|
41843e5253 |
Merge pull request 'Let the studio book lessons and record intake collected elsewhere' (#183) from feature/182-admin-booking-and-intake-recording into main
Release / Build and Publish Release (push) Successful in 4m43s
Release / Open next-version bump PR (push) Successful in 3s
CI / Tests (PHP 8.1) (push) Successful in 51s
CI / Tests (PHP 8.2) (push) Successful in 56s
CI / Tests (PHP 8.3) (push) Successful in 4m41s
CI / Tests (PHP 8.5) (push) Successful in 3m6s
CI / No Debug Code (push) Successful in 4s
CI / Coding Standards & Static Analysis (push) Successful in 8m23s
CI / Build Plugin Zip (push) Successful in 2m39s
Reviewed-on: #183v1.5.3 |
||
|
|
8c21a3fa9d
|
Let the studio book lessons and record intake collected elsewhere
CI / Tests (PHP 8.1) (pull_request) Successful in 6m39s
CI / Tests (PHP 8.2) (pull_request) Successful in 57s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m59s
CI / Tests (PHP 8.5) (pull_request) Successful in 3m31s
CI / No Debug Code (pull_request) Successful in 3s
CI / Coding Standards & Static Analysis (pull_request) Successful in 3m28s
CI / Build Plugin Zip (pull_request) Skipped
Two related gaps, closed together because the second is created by the first. A private lesson could only be booked by the student or their guardian, so a booking taken over the phone had no way in — where group classes have had "Add students directly" all along. "Book a lesson for a student" is now a panel on Scheduler and My Lessons: student, open time, lesson type, with weekly term reservations and a no-charge option for make-up lessons. The booking core is extracted to Booking\LessonBooker and shared with POST /bookings, so the two paths cannot drift on offering rules, slot claiming, or billing. That leaves a registration with no intake answers and no policy acceptances, because nobody was at a keyboard to give them — already true of every directly added group-class student. Ticking the boxes on a student's behalf would be an audit trail that says something untrue, so instead the answers are collected another way and recorded afterwards, from a lesson's or an enrolment's detail page. Every recording must say how it was collected, which is stamped on each row along with who typed it and shown in a new "How it was given" column: a policy ticked online and one transcribed from paper must never look alike. Only staff-made registrations qualify (us_lessons.booked_by, us_group_enrollments.enrolled_by) — one the student made already holds their own answers. Only what is still missing can be recorded, re-checked at write time, so a stale or double-posted form cannot duplicate or overwrite. No IP is stored for a transcription, and accepted_by stays the student while recorded_by names the staff member. Intake is now generic over Registration\IntakeSubject, which Lesson and Enrollment both implement; LessonDetail became Registration\IntakeAudit and is shared by both detail views rather than duplicated. Closes #182 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QfHt6CyJHz6KkA4RuaS7WK |
||
|
|
8a34ec41e9 |
Merge pull request 'Cache the packages php-builder installs, and restore PHP 8.5' (#181) from ci/cache-php-builder-deps into main
CI / No Debug Code (push) Successful in 3s
CI / Tests (PHP 8.2) (push) Successful in 2m27s
CI / Tests (PHP 8.1) (push) Successful in 2m33s
CI / Tests (PHP 8.3) (push) Successful in 2m55s
CI / Coding Standards & Static Analysis (push) Successful in 3m26s
CI / Tests (PHP 8.5) (push) Successful in 7m59s
CI / Build Plugin Zip (push) Successful in 6m59s
Reviewed-on: #181 |