Skip to content

Create ParticipantEvent when someone is invited - #149

Merged
leowilkin merged 3 commits into
hackclub:mainfrom
jollyroger182:feat/invite-create-participant-event
Sep 26, 2026
Merged

leowilkin merged 3 commits into
hackclub:mainfrom
jollyroger182:feat/invite-create-participant-event

Conversation

@jollyroger182

@jollyroger182 jollyroger182 commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Currently, a ParticipantEvent is not created when a participant is invited via the API. However, CSV imports do create a participant.

This PR unifies the two so that a ParticipantEvent is created when an invitation is created via the API. It also deletes all invitations for the email when a ParticipantEvent is deleted, so that deleting a ParticipantEvent also revokes their invitation.

jollyroger182 and others added 2 commits September 24, 2026 13:44
An Invitation is keyed by email, not by registration, so deleting a
ParticipantEvent left the invitation behind as a live key. The onboarding
controller rebuilds a registration from a surviving invitation whenever it
finds none for the signed-in person, so the original emailed link simply
re-registered them as in_progress.

The token route at least expires, but the no-token route (event selected
from the dashboard) matches on `expires_at > now OR accepted_at IS NOT
NULL`, and accepting happens on the first click of the invite link. An
invitation anyone has ever opened therefore never stopped working: an
invitation expired six months earlier and accepted a year earlier still
re-created the registration.

Deliberately not a destroy callback. ParticipantMergeService destroys a
registration to replace it with a more progressed duplicate, and an event
teardown destroys them wholesale; neither means "uninvite this person". It
is called from the two places that do mean it — the admin and API destroy
actions — each inside a transaction with the destroy.

Withdrawal is untouched: it stays reversible, and redirect_if_withdrawn
already catches a withdrawn person returning by their link.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNAizmNs7QmABqaVXa6Boy
The mail job was enqueued inside the transaction. When registering the
invitee failed validation, the invitation row rolled back but the job
still ran, and the mailer's find-or-create resurrected the invitation
and emailed a link with no registration behind it.

Invitation.issue! now delegates sending to a new deliver_later, which
the API calls once both rows are committed. The duplicate-registration
guard now matches email case-insensitively, like the lookup that
attaches the registration, and that lookup picks the oldest row when an
address has duplicate participant records.
@leowilkin
leowilkin merged commit 184fe45 into hackclub:main Sep 26, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants