fix(photon): use per-user assigned line for agent iMessage number

On shared-number plans, `/lines` has no dedicated entry, so the
`assignedPhoneNumber` field on the user object is the source of truth
for which number to text the agent. Fall back to the line inventory
only when no per-user assignment exists.
This commit is contained in:
underthestars-zhy 2026-06-08 17:13:16 -07:00 committed by Teknium
parent 314af28e86
commit 84e4b4b9a5
3 changed files with 53 additions and 11 deletions

View file

@ -751,6 +751,21 @@ def register_user_if_absent(
return user, True
def user_assigned_line(user: Optional[Dict[str, Any]]) -> Optional[str]:
"""Return the iMessage number a Spectrum user is assigned to text on.
This is the user's ``assignedPhoneNumber`` (the dashboard's "TEXTS ON"
column) i.e. the number to text to reach the agent, as opposed to the
user's own ``phoneNumber``. On shared-number plans there is no dedicated
entry in ``/lines``, so this per-user field is the source of truth.
Returns ``None`` when unset (e.g. a freshly created, not-yet-assigned user).
"""
if not user:
return None
val = user.get("assignedPhoneNumber")
return str(val) if val else None
# ---------------------------------------------------------------------------
# Dashboard API: iMessage lines (the assigned number inventory)

View file

@ -182,6 +182,7 @@ def _cmd_setup(args: argparse.Namespace) -> int:
Colors.CYAN,
)
)
agent_number = None
if not phone:
print(" Skipped user registration (no phone given). Re-run with --phone later.")
else:
@ -190,7 +191,7 @@ def _cmd_setup(args: argparse.Namespace) -> int:
first_name = args.first_name
email = args.email
try:
_user, created = photon_auth.register_user_if_absent(
user, created = photon_auth.register_user_if_absent(
token, dashboard_id,
phone_number=phone,
first_name=first_name,
@ -204,18 +205,26 @@ def _cmd_setup(args: argparse.Namespace) -> int:
print(f" user registration failed: {e}", file=sys.stderr)
return 1
print(" ✓ phone registered" if created else " ✓ phone already registered")
# The number to text the agent is the user's assigned iMessage line
# (the dashboard's "TEXTS ON" column). On shared-number plans there is
# no dedicated entry in /lines, so this per-user field is the source of
# truth — and we already have it from the (reused) user object.
agent_number = photon_auth.user_assigned_line(user)
# 5. Surface the assigned iMessage line (the number to text the agent).
try:
line = photon_auth.get_imessage_line(token, dashboard_id)
except Exception as e:
line = None
print(f" (could not fetch the assigned line: {e})", file=sys.stderr)
if line and line.get("phoneNumber"):
status = line.get("status") or "active"
# 5. Surface the agent's iMessage number (the number to text the agent).
if not agent_number:
# No per-user assignment — fall back to a dedicated line if the project
# has one provisioned in its line inventory.
try:
line = photon_auth.get_imessage_line(token, dashboard_id)
if line:
agent_number = line.get("phoneNumber")
except Exception as e:
print(f" (could not fetch the assigned line: {e})", file=sys.stderr)
if agent_number:
print()
print("┌─ Your agent's iMessage number ───────────────────────────────")
print(f"│ 📱 {line['phoneNumber']} ({status})")
print(f"│ 📱 {agent_number}")
print("│ Text this number from your phone to talk to your agent.")
print("└──────────────────────────────────────────────────────────────")
else:

View file

@ -329,7 +329,11 @@ def test_register_user_if_absent_dedup(monkeypatch: pytest.MonkeyPatch) -> None:
posted = {"n": 0}
def fake_get(url: str, **kwargs: Any) -> _FakeResponse:
return _FakeResponse(json_body=[{"id": "u1", "phoneNumber": "+1 (555) 123-4567"}])
return _FakeResponse(json_body=[{
"id": "u1",
"phoneNumber": "+1 (555) 123-4567",
"assignedPhoneNumber": "+16282679185",
}])
def fake_post(url: str, **kwargs: Any) -> _FakeResponse:
posted["n"] += 1
@ -344,6 +348,20 @@ def test_register_user_if_absent_dedup(monkeypatch: pytest.MonkeyPatch) -> None:
assert created is False
assert user["id"] == "u1"
assert posted["n"] == 0
# The reused user carries the assigned iMessage line ("TEXTS ON").
assert photon_auth.user_assigned_line(user) == "+16282679185"
def test_user_assigned_line() -> None:
assert (
photon_auth.user_assigned_line({"assignedPhoneNumber": "+16282679185"})
== "+16282679185"
)
# Own number present but no assignment yet (e.g. freshly created user).
assert photon_auth.user_assigned_line({"phoneNumber": "+15551234567"}) is None
assert photon_auth.user_assigned_line({"assignedPhoneNumber": ""}) is None
assert photon_auth.user_assigned_line({}) is None
assert photon_auth.user_assigned_line(None) is None
def test_register_user_if_absent_creates(monkeypatch: pytest.MonkeyPatch) -> None: