Files
projectsend/app/Modules/Clients/Http/Controllers
ignacionelson cd2ce960d3 Refuse an invitation whose address was taken while the link was live
An invitation stays live for days -- 72 hours by default -- and the address
it names can be claimed in that window: staff got impatient and created the
account by hand, or the person used the public registration form instead.
Redemption never asked, so User::create() met the unique index on
users.email and raised a QueryException. A 500, on the screen of somebody
who had just chosen a password, having done nothing wrong.

ClientProvisioning::addressIsFree() exists for exactly this, and its
docblock says who must call it: the paths with no form to validate. LDAP
asks. Redemption is the third such path and did not.

It now refuses with a message that says what happened, rather than the
generic "this invitation is no longer valid" the expired case uses. There
is nothing to withhold here -- whoever holds the link already knows the
address, because it is the one the invitation was sent to -- and being told
to sign in instead is the only useful thing to say.

The invitation stays pending rather than being retired. It is the account
that resolved the situation, not the link, and a retired row would only
make the second attempt read as expired.

The address rule spans soft-deleted accounts, the same as it does
everywhere else, so a deleted account still holds its address until erasure
takes the row away. Both cases are tested.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPk8qAs38pudYGWwmGkYPe
2026-09-12 14:30:42 -03:00
..
2026-09-08 16:23:34 -03:00
2026-08-14 01:38:12 -03:00