Note: branched from fix/invite-email-lock (PR #82) because both touch the registration page/template — merge #82 first and this PR reduces to just the group-link commit.
What & why
From the user demo: an admin option to generate a group invite link to include in a newsletter.
Invites admin page gains a Group Invite Link form with a required expiry date (the link stops working at the end of that day). The link is shown once, like personal invite links, and appears in the pending list as "Group link" with its expiry; it can be revoked.
The link is multi-use: it is never marked accepted, and anyone with it can register while it is pending and unexpired — in any registration mode, so invite-only studios can run a campaign.
The registration form collects an editable email for group links (personal invites keep the locked, prefilled email from #78).
Group signups must confirm their email (same hashed-token flow as open registration), but confirming skips admin approval: the account is approved on the spot, the student gets the approved email, and the page shows a "ready to use" notice with a sign-in link. They never appear under Pending Students.
Mechanics
us_invites grows kind (personal/group) and expires_at (dbDelta adds the columns via the existing version-bump upgrade path). An explicit expires_at overrides the personal 14-day window in Invite::isExpired().
RegistrationStatus::markPending($userId, autoApprove: true) stamps a us_auto_approve user meta; EmailConfirmationHandler::maybeConfirm() approves such accounts immediately after confirming (no admin heads-up email) and redirects with us_confirmed=ready.
Tests
New/updated coverage across InviteTest (expiry precedence, kind defaults), InviteRepositoryTest (persisted columns), RegistrationStatusTest (auto-approve marker lifecycle), EmailConfirmationHandlerTest (auto-approve vs. review-queue confirmation paths), and RegistrationPageTest (group signup creates a pending auto-approve account without login even in invite-only mode; group form shows an editable email).
composer test — 377 tests pass; composer lint (PHPStan level 10) and composer cs clean.
Closes #77
> **Note:** branched from `fix/invite-email-lock` (PR #82) because both touch the registration page/template — merge #82 first and this PR reduces to just the group-link commit.
## What & why
From the user demo: an admin option to generate a **group invite link** to include in a newsletter.
- **Invites admin page** gains a *Group Invite Link* form with a **required expiry date** (the link stops working at the end of that day). The link is shown once, like personal invite links, and appears in the pending list as "Group link" with its expiry; it can be revoked.
- The link is **multi-use**: it is never marked accepted, and anyone with it can register while it is pending and unexpired — **in any registration mode**, so invite-only studios can run a campaign.
- The registration form collects an **editable email** for group links (personal invites keep the locked, prefilled email from #78).
- Group signups must **confirm their email** (same hashed-token flow as open registration), but confirming **skips admin approval**: the account is approved on the spot, the student gets the approved email, and the page shows a "ready to use" notice with a sign-in link. They never appear under Pending Students.
## Mechanics
- `us_invites` grows `kind` (`personal`/`group`) and `expires_at` (dbDelta adds the columns via the existing version-bump upgrade path). An explicit `expires_at` overrides the personal 14-day window in `Invite::isExpired()`.
- `RegistrationStatus::markPending($userId, autoApprove: true)` stamps a `us_auto_approve` user meta; `EmailConfirmationHandler::maybeConfirm()` approves such accounts immediately after confirming (no admin heads-up email) and redirects with `us_confirmed=ready`.
## Tests
New/updated coverage across `InviteTest` (expiry precedence, kind defaults), `InviteRepositoryTest` (persisted columns), `RegistrationStatusTest` (auto-approve marker lifecycle), `EmailConfirmationHandlerTest` (auto-approve vs. review-queue confirmation paths), and `RegistrationPageTest` (group signup creates a pending auto-approve account without login even in invite-only mode; group form shows an editable email).
- `composer test` — 377 tests pass; `composer lint` (PHPStan level 10) and `composer cs` clean.
Docs updated: `docs/features/account-registration.md`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
A studio admin can generate a shareable group invite link (e.g. for a
newsletter) from the Invites page, choosing a required expiry date. Anyone
with the link may register while it is valid, in any registration mode: the
form collects their own email, they must confirm it via the usual hashed
token, and confirming approves the account immediately — group signups never
enter the Pending Students queue.
- us_invites grows kind (personal/group) and expires_at; an explicit expiry
wins over the personal 14-day window. Group links stay pending (multi-use)
until revoked or expired.
- RegistrationPage: group signups create the account pending with the
us_auto_approve marker and send the confirmation email; no auto-login.
- EmailConfirmationHandler: auto-approve accounts are approved on
confirmation, emailed the approved notice, and redirected to a new
us_confirmed=ready notice with a sign-in link.
Closes#77
Co-Authored-By: Claude Fable 5 <[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.
Closes #77
What & why
From the user demo: an admin option to generate a group invite link to include in a newsletter.
Mechanics
us_invitesgrowskind(personal/group) andexpires_at(dbDelta adds the columns via the existing version-bump upgrade path). An explicitexpires_atoverrides the personal 14-day window inInvite::isExpired().RegistrationStatus::markPending($userId, autoApprove: true)stamps aus_auto_approveuser meta;EmailConfirmationHandler::maybeConfirm()approves such accounts immediately after confirming (no admin heads-up email) and redirects withus_confirmed=ready.Tests
New/updated coverage across
InviteTest(expiry precedence, kind defaults),InviteRepositoryTest(persisted columns),RegistrationStatusTest(auto-approve marker lifecycle),EmailConfirmationHandlerTest(auto-approve vs. review-queue confirmation paths), andRegistrationPageTest(group signup creates a pending auto-approve account without login even in invite-only mode; group form shows an editable email).composer test— 377 tests pass;composer lint(PHPStan level 10) andcomposer csclean.Docs updated:
docs/features/account-registration.md.🤖 Generated with Claude Code