""" Whether the hub mails an invitation is the inviter's choice, and it is remembered. Mailing it hands the hub the code — `invite-notify` writes it into the message — which is exactly what §3.4 says the code is for not doing. So the Members tab offers it as a box, checked by default, and an unchecked box must mean the hub is never asked. The choice lives in an account preference; a key the hub does not list is refused, and the box would snap back on every click with nothing on screen to say why. """ import base64 import re from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" SETTINGS = ROOT / "static" / "group-settings.js" USERS = ROOT / "api" / "users.py" def _pref_key() -> str: m = re.search(r"^export const INVITE_EMAIL_PREF = '([^']+)';", SETTINGS.read_text(encoding="utf-8"), re.M) assert m, "group-settings.js no longer declares INVITE_EMAIL_PREF" return m.group(1) def test_hub_accepts_the_key_the_client_writes(): allowed = re.search(r"ALLOWED_PREF_KEYS = frozenset\(\[(.*?)\]\)", USERS.read_text(encoding="utf-8"), re.S).group(1) assert f'"{_pref_key()}"' in allowed def test_an_unchecked_box_never_reaches_invite_notify(): """The only call to `invite-notify` sits inside the branch the box opens.""" src = SETTINGS.read_text(encoding="utf-8") calls = [m.start() for m in re.finditer(r"/invite-notify`", src)] assert len(calls) == 1, "expected exactly one invite-notify call in group-settings.js" guard = src.rfind("if (inviteByEmail) {", 0, calls[0]) assert guard != -1, "invite-notify is called without checking the box" # The guarded block must still be open where the call is: no closing brace # at the guard's own indentation between the two. indent = src[src.rfind("\n", 0, guard) + 1:guard] assert f"\n{indent}}}" not in src[guard:calls[0]], ( "the box's branch closes before the invite-notify call") @pytest.mark.asyncio async def test_the_choice_is_remembered(client): auth_key = base64.b64encode(b"k" * 32).decode() r = await client.post("/v1/users/register", json={ "username": "invite_mailer", "email": "invite_mailer@example.test", "auth_key": auth_key}) assert r.status_code == 201, r.text r = await client.post("/v1/users/login", json={ "username": "invite_mailer", "auth_key": auth_key}) assert r.status_code == 200, r.text headers = {"Authorization": f"Bearer {r.json()['access_token']}"} key = _pref_key() r = await client.put(f"/v1/users/me/preferences/{key}", headers=headers, json={"value": "false"}) assert r.status_code == 200, r.text r = await client.get("/v1/users/me/preferences", headers=headers) assert r.json().get(key) == "false"