Adds an enrolment deadline to group classes, set by the instructor, defaulting to the first day of the class. Once it passes, students can no longer self-enrol — but instructors keep a manual late-enrolment path.
Details
Deadline — new us_offerings.enrollment_deadline (DATE, nullable). Offering::effectiveEnrollmentDeadline() resolves it to the stored date or term_start (first class day) when unset; Offering::isEnrollmentOpen($today) is an inclusive Y-m-d comparison (the deadline day itself stays open).
Enforcement — EnrollmentEndpoint::enroll rejects late self-enrolment with 403 enrollment_closed; the front-end group-class list shows "Enrolment has closed." in place of the Enrol button.
Instructor UI — the offering admin form gains a date field (blank = default). The class details page shows the deadline.
Late enrolment — the Add students directly control on the class details page now renders for public classes too (previously invite-only only) and deliberately bypasses the deadline and capacity, so an instructor can enrol a student after the class has closed. Past the deadline the page labels these as late enrolments.
Bumps USC_VERSION to 1.1.3 for the schema change (so dbDelta re-runs on existing sites).
Tests
All green:
composer test — 525 tests, 1513 assertions
composer lint — PHPStan level 10 clean
composer cs — PHPCS clean
Added model, controller, and endpoint coverage for the deadline resolution, the closed-enrolment rejection, and the public-class direct-add / late-enrolment note.
## What
Adds an **enrolment deadline** to group classes, set by the instructor, defaulting to the first day of the class. Once it passes, students can no longer self-enrol — but instructors keep a manual **late-enrolment** path.
## Details
- **Deadline** — new `us_offerings.enrollment_deadline` (DATE, nullable). `Offering::effectiveEnrollmentDeadline()` resolves it to the stored date or `term_start` (first class day) when unset; `Offering::isEnrollmentOpen($today)` is an inclusive `Y-m-d` comparison (the deadline day itself stays open).
- **Enforcement** — `EnrollmentEndpoint::enroll` rejects late self-enrolment with `403 enrollment_closed`; the front-end group-class list shows "Enrolment has closed." in place of the Enrol button.
- **Instructor UI** — the offering admin form gains a date field (blank = default). The class details page shows the deadline.
- **Late enrolment** — the **Add students directly** control on the class details page now renders for public classes too (previously invite-only only) and deliberately bypasses the deadline and capacity, so an instructor can enrol a student after the class has closed. Past the deadline the page labels these as late enrolments.
- Bumps `USC_VERSION` to 1.1.3 for the schema change (so `dbDelta` re-runs on existing sites).
## Tests
All green:
- `composer test` — 525 tests, 1513 assertions
- `composer lint` — PHPStan level 10 clean
- `composer cs` — PHPCS clean
Added model, controller, and endpoint coverage for the deadline resolution, the closed-enrolment rejection, and the public-class direct-add / late-enrolment note.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Group classes gain an instructor-set enrolment deadline (new
us_offerings.enrollment_deadline column) that defaults to the first day of
the class (term_start). Past the deadline students can no longer self-enrol:
the enrolment endpoint rejects it (403 enrollment_closed) and the front-end
class list shows "Enrolment has closed." in place of the Enrol button.
Instructors keep a manual path: the "Add students directly" control on each
class's details page now renders for public classes too (not just
invite-only) and deliberately bypasses the deadline and capacity, so a
student can be added as a late enrolment after the class has closed. Past
the deadline the details page labels these as late enrolments.
Bumps USC_VERSION to 1.1.3 for the schema change.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
The front end used the deadline only to gate the Enrol button; students had
no way to see when enrolment closes. Add an "Enrol by <date>" line to each
class card, shown while enrolment is still open, for the effective deadline
(the instructor's date, or the first class day by default).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
Adds an enrolment deadline to group classes, set by the instructor, defaulting to the first day of the class. Once it passes, students can no longer self-enrol — but instructors keep a manual late-enrolment path.
Details
us_offerings.enrollment_deadline(DATE, nullable).Offering::effectiveEnrollmentDeadline()resolves it to the stored date orterm_start(first class day) when unset;Offering::isEnrollmentOpen($today)is an inclusiveY-m-dcomparison (the deadline day itself stays open).EnrollmentEndpoint::enrollrejects late self-enrolment with403 enrollment_closed; the front-end group-class list shows "Enrolment has closed." in place of the Enrol button.USC_VERSIONto 1.1.3 for the schema change (sodbDeltare-runs on existing sites).Tests
All green:
composer test— 525 tests, 1513 assertionscomposer lint— PHPStan level 10 cleancomposer cs— PHPCS cleanAdded model, controller, and endpoint coverage for the deadline resolution, the closed-enrolment rejection, and the public-class direct-add / late-enrolment note.
🤖 Generated with Claude Code