Skip to content

fix(sms): stop the SMS settings screen editing the login number - #552

Open
MOHITKOURAV01 wants to merge 1 commit into
ishita2740:mainfrom
MOHITKOURAV01:fix/issue-547-sms-settings-login-phone
Open

fix(sms): stop the SMS settings screen editing the login number#552
MOHITKOURAV01 wants to merge 1 commit into
ishita2740:mainfrom
MOHITKOURAV01:fix/issue-547-sms-settings-login-phone

Conversation

@MOHITKOURAV01

Copy link
Copy Markdown
Contributor

Closes #547.

POST /sms/settings wrote the number it was given into three fields:

UserService.update_user(current_user["id"], {
    "phone": phone or "",
    "sms_phone_number": phone or "",
    "sms_enabled": settings.enabled,
})

phone is not an SMS field. It is what firebase_login resolves an
account by, through UserService.get_user_by_phone. So the SMS
preferences screen was editing the credential, and phone or "" meant a
user who cleared the box and unticked the toggle erased it — the next
sign-in with her own number matched nothing, took the create-a-new-account
branch, and left her cycle history under an id nothing reaches.

What changed

phone is no longer written here. The two fields now mean exactly
one thing each: phone is who the account is, sms_phone_number is
where its summaries go. That also removes the collision described in the
issue — one account writing another's login number over its own — rather
than guarding against it, since the field a uniqueness check would
protect is no longer touched by this route.

A toggle is not a deletion. Turning summaries off and forgetting the
number are different intentions and only one costs the user retyping.
SMSSettings.phone_was_submitted reads model_fields_set, so
{"enabled": false} leaves the saved number alone while
{"phoneNumber": "", "enabled": false} clears it. Both arrive as
normalized_phone is None once parsed, so the difference has to come
from which keys the JSON actually carried.

registered_phone prefers sms_phone_number, falling back to
phone.
This reverses the previous order, and the reversal is
required by the change above rather than incidental to it: the old order
was correct only while POST /settings wrote both fields to the same
value. With that write removed, preferring phone would make saving an
SMS number a no-op for every account that has a login number — the
screen would keep showing, and the summary keep going to, the number she
did not choose. The fallback is what keeps accounts that have never
opened this screen behaving exactly as before.

The response is re-read rather than echoed. What comes back has to be
the number a summary would actually go to; after a request that cleared
sms_phone_number that is the account number the fallback resolves to,
not the empty string the caller submitted.

Tests

backend/tests/test_sms_settings_identity.py — 12 cases. Two notes on
how they are written:

  • They assert on the stored user document, not on the response body.
    A 200 says the request was accepted; only users/{id}.phone says
    whether the login number survived, and a response-body test would have
    passed against the original code, which echoed the number back either
    way.
  • test_the_account_can_still_sign_in_after_the_settings_are_cleared
    drives the real firebase_login route. "You can no longer log in" is
    the actual failure; a field assertion is a proxy for it, and a proxy is
    what let this ship. It checks is_new_user and confirms the same
    account id from the other side via /auth/me, so it does not rest on
    that one flag being reported correctly.

One existing assertion in test_sms_destination_binding.py is reversed —
test_registered_phone_prefers_the_same_field_the_settings_screen_shows
becomes test_registered_phone_prefers_the_number_chosen_for_sms. It
encoded the old precedence, which this change deliberately inverts for
the reason above; the property it was actually protecting (the settings
screen and the send path agree with each other) still holds, since both
still call the same function, and
test_settings_and_send_agree_on_the_destination still asserts it end to
end.

Full backend suite green.

Out of scope

PATCH /auth/profile also accepts phone with no uniqueness check —
the same shape as #531 for email. Noted in the issue so it is not lost;
not touched here.

`POST /sms/settings` wrote the number it was given into `phone` as well
as `sms_phone_number`. `phone` is what `firebase_login` resolves an
account by, so an SMS preferences screen was editing the credential —
and `phone or ""` meant clearing the box and unticking the toggle erased
it, leaving the user unable to sign in and her history stranded under an
id nothing reaches.

The route now writes only where summaries go, and only when the caller
said something about it: sending just `{"enabled": false}` turns
summaries off without forgetting the number, while an explicit empty
string still clears it.

`registered_phone` prefers `sms_phone_number` and falls back to `phone`.
The order is reversed from before, which was correct only while both
fields held the same value; keeping `phone` first would have made saving
an SMS number a no-op for anyone with a login number. The fallback keeps
accounts that have never opened this screen behaving exactly as before.

Closes ishita2740#547
@vercel

vercel Bot commented Aug 28, 2026

Copy link
Copy Markdown

@MOHITKOURAV01 is attempting to deploy a commit to the ishita2740's projects Team on Vercel.

A member of the Team first needs to authorize it.

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.

[Backend] Saving SMS settings overwrites the phone number the account signs in with — and turning summaries off erases it

1 participant