feat(auth): M3 §10 绑微信按默认替换展示昵称头像(共享 helper 接两路径)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -178,6 +178,27 @@ def test_rebind_creates_new_account_and_binds_openid(client, monkeypatch) -> Non
|
||||
assert r.json()["token"]["user"]["id"] == y["id"]
|
||||
|
||||
|
||||
# ===== §10: continue 路径也应用展示身份回填规则 =====
|
||||
|
||||
def test_continue_applies_section10(client, monkeypatch) -> None:
|
||||
"""§10 via M2 attach 路径: X 是默认昵称+null头像的 sms 账号;
|
||||
continue 绑定微信后,展示昵称/头像应被微信值替换,并体现在响应的 token.user 中。"""
|
||||
phone = "13900139211"
|
||||
_sms_occupy(client, phone) # 建 X:默认昵称, null avatar
|
||||
body = _occupy_via_conflict(
|
||||
client, monkeypatch, "openid_s10", phone, "devS10"
|
||||
) # fake_userinfo 默认 nickname="微信昵称", avatar="http://x/a.png"
|
||||
|
||||
r = client.post(
|
||||
"/api/v1/auth/wechat/conflict/continue",
|
||||
json={"conflict_ticket": body["conflict_ticket"], "device_id": "devS10"},
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
user_out = r.json()["token"]["user"]
|
||||
assert user_out["nickname"] == "微信昵称"
|
||||
assert user_out["avatar_url"] == "http://x/a.png"
|
||||
|
||||
|
||||
def test_rebind_blocked_within_30_days(client, monkeypatch) -> None:
|
||||
"""同一手机号 30 天内二次换绑 → 409;占用响应 rebind_available=False。"""
|
||||
phone = "13900139302"
|
||||
|
||||
@@ -312,6 +312,94 @@ def test_bind_rejects_openid_already_bound(client, monkeypatch) -> None:
|
||||
assert r.status_code == 409, r.text
|
||||
|
||||
|
||||
# ===== §10 绑微信时展示身份回填规则 =====
|
||||
|
||||
def test_bind_replaces_default_nickname_and_null_avatar(client, monkeypatch) -> None:
|
||||
"""§10-A: 全默认(昵称=系统默认,头像=null) → 绑微信后两个展示字段都替换为微信值。"""
|
||||
monkeypatch.setattr(
|
||||
"app.integrations.wxpay.code_to_userinfo",
|
||||
lambda code: {"openid": "openid_s10_a", "nickname": "微信昵称A", "avatar_url": "https://x/a.png", "raw": {}},
|
||||
)
|
||||
token = _login(client, "13800003001")
|
||||
r = client.post("/api/v1/wallet/bind-wechat", json={"code": "c"}, headers=_auth(token))
|
||||
assert r.status_code == 200, r.text
|
||||
|
||||
r = client.get("/api/v1/auth/me", headers=_auth(token))
|
||||
assert r.status_code == 200, r.text
|
||||
body = r.json()
|
||||
assert body["nickname"] == "微信昵称A"
|
||||
assert body["avatar_url"] == "https://x/a.png"
|
||||
|
||||
|
||||
def test_bind_keeps_customized_nickname(client, monkeypatch) -> None:
|
||||
"""§10-B: 用户已改过昵称 → 绑微信后昵称保留,但 null 头像仍替换为微信头像。"""
|
||||
monkeypatch.setattr(
|
||||
"app.integrations.wxpay.code_to_userinfo",
|
||||
lambda code: {"openid": "openid_s10_b", "nickname": "微信昵称B", "avatar_url": "https://x/b.png", "raw": {}},
|
||||
)
|
||||
token = _login(client, "13800003002")
|
||||
# 先把昵称改成非默认值
|
||||
r = client.patch(
|
||||
"/api/v1/user/profile", json={"nickname": "我的名字"}, headers=_auth(token)
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
|
||||
r = client.post("/api/v1/wallet/bind-wechat", json={"code": "c"}, headers=_auth(token))
|
||||
assert r.status_code == 200, r.text
|
||||
|
||||
r = client.get("/api/v1/auth/me", headers=_auth(token))
|
||||
body = r.json()
|
||||
assert body["nickname"] == "我的名字" # 保留自定义昵称
|
||||
assert body["avatar_url"] == "https://x/b.png" # null 头像被微信头像替换
|
||||
|
||||
|
||||
def test_bind_keeps_customized_avatar(client, monkeypatch) -> None:
|
||||
"""§10-C: 已有自定义头像 → 绑微信后头像保留,但默认昵称替换为微信昵称。"""
|
||||
monkeypatch.setattr(
|
||||
"app.integrations.wxpay.code_to_userinfo",
|
||||
lambda code: {"openid": "openid_s10_c", "nickname": "微信昵称C", "avatar_url": "https://x/c.png", "raw": {}},
|
||||
)
|
||||
token = _login(client, "13800003003")
|
||||
phone = "13800003003"
|
||||
# 直接用 DB 给用户写入自定义头像(保持默认昵称)
|
||||
db = SessionLocal()
|
||||
try:
|
||||
user = db.execute(select(User).where(User.phone == phone)).scalar_one()
|
||||
user.avatar_url = "https://custom/av.png"
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
r = client.post("/api/v1/wallet/bind-wechat", json={"code": "c"}, headers=_auth(token))
|
||||
assert r.status_code == 200, r.text
|
||||
|
||||
r = client.get("/api/v1/auth/me", headers=_auth(token))
|
||||
body = r.json()
|
||||
assert body["nickname"] == "微信昵称C" # 默认昵称被替换
|
||||
assert body["avatar_url"] == "https://custom/av.png" # 自定义头像保留
|
||||
|
||||
|
||||
def test_bind_wechat_empty_keeps_default(client, monkeypatch) -> None:
|
||||
"""§10-D: 微信侧 nickname/avatar 均为 None → 不覆盖,展示字段维持原默认值。"""
|
||||
monkeypatch.setattr(
|
||||
"app.integrations.wxpay.code_to_userinfo",
|
||||
lambda code: {"openid": "openid_s10_d", "nickname": None, "avatar_url": None, "raw": {}},
|
||||
)
|
||||
token = _login(client, "13800003004")
|
||||
|
||||
r = client.get("/api/v1/auth/me", headers=_auth(token))
|
||||
original_nickname = r.json()["nickname"] # 系统分配的默认昵称
|
||||
assert original_nickname.startswith("用户")
|
||||
|
||||
r = client.post("/api/v1/wallet/bind-wechat", json={"code": "c"}, headers=_auth(token))
|
||||
assert r.status_code == 200, r.text
|
||||
|
||||
r = client.get("/api/v1/auth/me", headers=_auth(token))
|
||||
body = r.json()
|
||||
assert body["nickname"] == original_nickname # 默认昵称不变
|
||||
assert body["avatar_url"] is None # 头像仍为 null
|
||||
|
||||
|
||||
def test_withdraw_reject_refunds(client, monkeypatch) -> None:
|
||||
"""管理员审核拒绝 → 退回现金 + 单 rejected + 理由写入 fail_reason(用户可见)。"""
|
||||
monkeypatch.setattr("app.integrations.wxpay.code_to_userinfo", lambda code: {"openid": "openid_reject", "nickname": None, "avatar_url": None, "raw": {}})
|
||||
|
||||
Reference in New Issue
Block a user