Skip to content

Let the teacher see who never got in, and send the invitation again - #54

Merged
yt314 merged 1 commit into
tests-that-fail-at-nightfrom
resend-the-invitation
Sep 24, 2026
Merged

yt314 merged 1 commit into
tests-that-fail-at-nightfrom
resend-the-invitation

Conversation

@yt314

@yt314 yt314 commented Sep 19, 2026 •

Copy link
Copy Markdown
Owner

Based on #53, so this diff stays readable. Merge that one first and this retargets to main on its own.

Adding a parent or a student creates their account and emails them an invitation to set a password. That email goes out exactly once, and a send that fails is only written to the log — AccountProvisioning catches the exception on purpose, so the teacher's save does not fail because of a mail server:

try { await emailSender.SendAsync(user.Email!, "הזמנה לתלמידון — קביעת סיסמה", html); }
catch (Exception ex) { logger.LogError(ex, "Failed to send invitation email."); }

That is the right call for the save. But it means a parent who never received the invitation — a failed send, a spam folder, a link that has since expired — had no way in, and the teacher had no way to help her. I searched the whole app: there was no resend anywhere, and nothing on any screen said whether an invitation had ever been accepted. StudentListItemDto carried HasLogin (an address exists) but not whether anyone had ever used it.

The recovery that did exist was "שכחתי סיסמה" — which only helps a parent who knows she has an account, which is exactly what she does not know if the email never arrived.

Where the answer already was

Setting a password from the invitation is what verifies the address:

// קביעת סיסמה דרך קישור ההזמנה מוכיחה בעלות על המייל
if (!user.EmailConfirmed) { user.EmailConfirmed = true; … }

So EmailConfirmed already records who has come in. It just never reached the teacher. It now travels on both lists as AccountActivated, the students screen marks whoever is still waiting, and a button next to the mark sends the invitation again.

Verified against the running app

A newly created parent:

create parent: HTTP 201
{"fullName":"תמר בדיקה", … ,"accountActivated":false}

ROW: תב  תמר בדיקה  tamar.test…@talmidon.local  050-3334444  0  ממתין/ה להפעלה
resend button present: 1
emails before resend: 1
TOAST: "ההזמנה נשלחה שוב  tamar.test…@talmidon.local"
emails after resend : 2

A real second email, counted in the mail sink — not just a reassuring toast.

Then she walks the link and sets a password:

set-password: HTTP 200
--- parent row now ---           {"fullName":"תמר בדיקה", … ,"accountActivated":true}
--- resend after activation ---  HTTP 409  {"message":"ההורה כבר קבע סיסמה ואין צורך בהזמנה חדשה."}

The mark and the button are gone, and the endpoint refuses.

Refused where it would be wrong

The address belongs to a real person, so the endpoint is not a button anyone can point anywhere:

another teacher resending someone else's parent : HTTP 404   (tenant filter)
a parent trying it                              : HTTP 403   (role)
someone who already set a password              : HTTP 409
a student with no sign-in of her own            : HTTP 409

Testing

  • dotnet test — 255 passing, including five new ones in ResendInvitationTests covering each line of that table plus the list flag flipping from false to true once a password is set.
  • npx ng build and npx vitest run — clean, 30 passing.
  • The whole loop walked in the browser and against the API, as quoted above.

Demo data restored and verified: the test parent was deleted, and the parents are back to דוד כהן and אסתר ברגר with 3 students.

Adding a parent or a student creates their account and emails them an
invitation to set a password. That email goes out exactly once, and a send
that fails is only written to the log — AccountProvisioning catches the
exception so the teacher's save does not fail with it.

So a parent who never received it — a failed send, a spam folder, a link
that expired — had no way in, and the teacher had no way to help her and no
way to even know. There was no resend anywhere in the app.

Setting a password from the invitation is what verifies the address, so
EmailConfirmed already says who has come in. That now reaches the lists as
AccountActivated, the students screen marks the ones still waiting, and a
button next to them sends the invitation again.

Refused where it would be wrong: someone who already set a password (409),
a student with no sign-in of her own (409), and another teacher's parent
(404, through the tenant filter).
@vercel

vercel Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
talmidon Ready Ready Preview Sep 19, 2026 10:30pm UTC

@yt314
yt314 merged commit 1f75613 into tests-that-fail-at-night Sep 24, 2026
2 checks passed

This branch was successfully deployed

1 active deployment
Preview — d4877fca Deployed Sep 19, 2026 by vercel[bot]
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.

1 participant