's'
This commit is contained in:
@@ -333,13 +333,52 @@ async def nomadvip_check_vip(user_id: str = ""):
|
||||
from ..services.pb import get_pb_client
|
||||
|
||||
pb = get_pb_client()
|
||||
linked_user_id = ""
|
||||
if not _uid_has_vip(pb, user_id):
|
||||
logging.info("[payjsapi] check_vip miss user_id=%s vip=False", user_id)
|
||||
result = {"vip": False}
|
||||
_cache_set(cache_key, result)
|
||||
return result
|
||||
# 关键补链:真实 wechat userid 可通过 vip_email_link.anonymous_user_id 关联到会员 user_id
|
||||
try:
|
||||
link_rec = pb.collection("vip_email_link").get_list(
|
||||
1, 1, {"filter": f'anonymous_user_id = "{user_id}"'}
|
||||
)
|
||||
if link_rec.items:
|
||||
linked_user_id = (
|
||||
_record_get(link_rec.items[0], "user_id", "") or ""
|
||||
).strip()
|
||||
except Exception:
|
||||
linked_user_id = ""
|
||||
if not linked_user_id:
|
||||
try:
|
||||
admin_token = _get_pb_admin_token()
|
||||
wx_record = (
|
||||
_pb_get_wechat_private_user(admin_token, user_id)
|
||||
if admin_token
|
||||
else None
|
||||
)
|
||||
wx_link = _extract_wechat_vip_link(wx_record)
|
||||
linked_user_id = (
|
||||
str(wx_link.get("pb_user_id", "")).strip()
|
||||
or str(wx_link.get("anonymous_user_id", "")).strip()
|
||||
)
|
||||
except Exception:
|
||||
linked_user_id = ""
|
||||
if not linked_user_id or not _uid_has_vip(pb, linked_user_id):
|
||||
logging.info("[payjsapi] check_vip miss user_id=%s vip=False", user_id)
|
||||
result = {"vip": False}
|
||||
_cache_set(cache_key, result)
|
||||
return result
|
||||
|
||||
email = _get_linked_email_for_user(pb, user_id)
|
||||
if not email and linked_user_id:
|
||||
try:
|
||||
link_rec = pb.collection("vip_email_link").get_list(
|
||||
1, 1, {"filter": f'user_id = "{linked_user_id}"'}
|
||||
)
|
||||
if link_rec.items:
|
||||
email = (
|
||||
_record_get(link_rec.items[0], "email", "") or ""
|
||||
).strip().lower()
|
||||
except Exception:
|
||||
pass
|
||||
if not email:
|
||||
admin_token = _get_pb_admin_token()
|
||||
if admin_token and user_id.startswith("user") and user_id[4:].isdigit():
|
||||
@@ -355,6 +394,8 @@ async def nomadvip_check_vip(user_id: str = ""):
|
||||
email or "(none)",
|
||||
)
|
||||
result = {"vip": True, "email": email}
|
||||
if linked_user_id:
|
||||
result["linked_user_id"] = linked_user_id
|
||||
_cache_set(cache_key, result)
|
||||
return result
|
||||
except Exception as error:
|
||||
@@ -398,6 +439,76 @@ def _pb_get_wechat_private_user(admin_token: str, wechat_userid: str) -> dict |
|
||||
return items[0] if items else None
|
||||
|
||||
|
||||
def _extract_wechat_vip_link(record: dict | None) -> dict:
|
||||
if not isinstance(record, dict):
|
||||
return {}
|
||||
raw_contact = record.get("raw_contact")
|
||||
if isinstance(raw_contact, str):
|
||||
try:
|
||||
import json as _json
|
||||
|
||||
raw_contact = _json.loads(raw_contact)
|
||||
except Exception:
|
||||
raw_contact = {}
|
||||
if not isinstance(raw_contact, dict):
|
||||
return {}
|
||||
link = raw_contact.get("_vip_link")
|
||||
return link if isinstance(link, dict) else {}
|
||||
|
||||
|
||||
def _pb_bind_wechat_vip_link(
|
||||
admin_token: str,
|
||||
wechat_userid: str,
|
||||
*,
|
||||
email: str | None = None,
|
||||
pb_user_id: str | None = None,
|
||||
anonymous_user_id: str | None = None,
|
||||
):
|
||||
"""
|
||||
在 wechat_private_users.raw_contact 中记录 _vip_link 关系。
|
||||
注意:不改变历史 user_id 语义,anonymous_user_id 仍是历史业务 user_id。
|
||||
"""
|
||||
record = _pb_get_wechat_private_user(admin_token, wechat_userid)
|
||||
if not isinstance(record, dict):
|
||||
return
|
||||
record_id = str(record.get("id", "")).strip()
|
||||
if not record_id:
|
||||
return
|
||||
|
||||
raw_contact = record.get("raw_contact")
|
||||
if isinstance(raw_contact, str):
|
||||
try:
|
||||
import json as _json
|
||||
|
||||
raw_contact = _json.loads(raw_contact)
|
||||
except Exception:
|
||||
raw_contact = {}
|
||||
if not isinstance(raw_contact, dict):
|
||||
raw_contact = {}
|
||||
|
||||
current = _extract_wechat_vip_link(record)
|
||||
raw_contact["_vip_link"] = {
|
||||
"email": (email or current.get("email") or "").strip().lower() or None,
|
||||
"pb_user_id": (pb_user_id or current.get("pb_user_id") or "").strip() or None,
|
||||
"anonymous_user_id": (
|
||||
anonymous_user_id or current.get("anonymous_user_id") or ""
|
||||
).strip()
|
||||
or None,
|
||||
"updated_at": int(time.time()),
|
||||
}
|
||||
|
||||
base = (PB_URL or "").rstrip("/")
|
||||
_http_session.patch(
|
||||
f"{base}/api/collections/wechat_private_users/records/{record_id}",
|
||||
json={"raw_contact": raw_contact},
|
||||
headers={
|
||||
"Authorization": f"Bearer {admin_token}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
timeout=DEFAULT_HTTP_TIMEOUT,
|
||||
)
|
||||
|
||||
|
||||
def _pb_get_user_by_id(admin_token: str, user_id: str) -> dict | None:
|
||||
base = (PB_URL or "").rstrip("/")
|
||||
response = _http_session.get(
|
||||
@@ -493,12 +604,22 @@ async def nomadvip_wechat_profile(item: dict):
|
||||
)
|
||||
if email and effective_member_user_id:
|
||||
try:
|
||||
# 保持历史语义:vip_email_link.anonymous_user_id 仍仅承载历史业务 user_id
|
||||
link_anonymous_id = anonymous_user_id or None
|
||||
_pb_upsert_email_link(
|
||||
admin_token,
|
||||
email,
|
||||
effective_member_user_id,
|
||||
anonymous_user_id or None,
|
||||
link_anonymous_id,
|
||||
)
|
||||
if wechat_userid:
|
||||
_pb_bind_wechat_vip_link(
|
||||
admin_token,
|
||||
wechat_userid,
|
||||
email=email,
|
||||
pb_user_id=effective_member_user_id,
|
||||
anonymous_user_id=link_anonymous_id,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -1124,6 +1245,7 @@ async def nomadvip_check_vip_by_email(item: dict):
|
||||
anonymous_user_id = (
|
||||
item.get("user_id") or item.get("anonymousUserId") or ""
|
||||
).strip()
|
||||
wechat_userid = (item.get("wechat_userid") or item.get("userid") or "").strip()
|
||||
logging.info(
|
||||
"[payjsapi] check_vip_by_email email=%s user_id=%s",
|
||||
email or "(empty)",
|
||||
@@ -1132,7 +1254,7 @@ async def nomadvip_check_vip_by_email(item: dict):
|
||||
|
||||
if not email or not password:
|
||||
return {"vip": False, "error": "missing email or password"}
|
||||
cache_key = f"check_vip_by_email:{email}:{anonymous_user_id}"
|
||||
cache_key = f"check_vip_by_email:{email}:{anonymous_user_id}:{wechat_userid}"
|
||||
cached = _cache_get(cache_key)
|
||||
if cached is not None:
|
||||
return cached
|
||||
@@ -1175,11 +1297,8 @@ async def nomadvip_check_vip_by_email(item: dict):
|
||||
pb = get_pb_client()
|
||||
matched_user_id = None
|
||||
vip_check_cache: dict[str, bool] = {}
|
||||
recovered_anonymous_user_id = (
|
||||
anonymous_user_id
|
||||
if anonymous_user_id.startswith("user") and anonymous_user_id[4:].isdigit()
|
||||
else None
|
||||
)
|
||||
# 保持历史语义:匿名ID只来自历史 user_id,不使用真实 wechat userid 覆盖
|
||||
recovered_anonymous_user_id = (anonymous_user_id or None)
|
||||
recovery_source = None
|
||||
|
||||
def has_vip_cached(uid: str) -> bool:
|
||||
@@ -1216,9 +1335,9 @@ async def nomadvip_check_vip_by_email(item: dict):
|
||||
if not has_vip_cached(linked_uid):
|
||||
continue
|
||||
matched_user_id = linked_uid
|
||||
if linked_anonymous_user_id.startswith("user") and linked_anonymous_user_id[4:].isdigit():
|
||||
if linked_anonymous_user_id:
|
||||
recovered_anonymous_user_id = linked_anonymous_user_id
|
||||
elif linked_uid.startswith("user") and linked_uid[4:].isdigit():
|
||||
elif linked_uid:
|
||||
recovered_anonymous_user_id = linked_uid
|
||||
recovery_source = "vip_email_link"
|
||||
break
|
||||
@@ -1250,6 +1369,14 @@ async def nomadvip_check_vip_by_email(item: dict):
|
||||
)
|
||||
else:
|
||||
_pb_upsert_email_link(admin_token, email, pb_user_id)
|
||||
if wechat_userid:
|
||||
_pb_bind_wechat_vip_link(
|
||||
admin_token,
|
||||
wechat_userid,
|
||||
email=email,
|
||||
pb_user_id=pb_user_id,
|
||||
anonymous_user_id=recovered_anonymous_user_id,
|
||||
)
|
||||
|
||||
logging.info(
|
||||
"[payjsapi] check_vip_by_email recovered by %s matched_user_id=%s effectiveUserId=%s anonymousUserId=%s",
|
||||
|
||||
Reference in New Issue
Block a user