'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
|
from ..services.pb import get_pb_client
|
||||||
|
|
||||||
pb = get_pb_client()
|
pb = get_pb_client()
|
||||||
|
linked_user_id = ""
|
||||||
if not _uid_has_vip(pb, user_id):
|
if not _uid_has_vip(pb, user_id):
|
||||||
|
# 关键补链:真实 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)
|
logging.info("[payjsapi] check_vip miss user_id=%s vip=False", user_id)
|
||||||
result = {"vip": False}
|
result = {"vip": False}
|
||||||
_cache_set(cache_key, result)
|
_cache_set(cache_key, result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
email = _get_linked_email_for_user(pb, user_id)
|
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:
|
if not email:
|
||||||
admin_token = _get_pb_admin_token()
|
admin_token = _get_pb_admin_token()
|
||||||
if admin_token and user_id.startswith("user") and user_id[4:].isdigit():
|
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)",
|
email or "(none)",
|
||||||
)
|
)
|
||||||
result = {"vip": True, "email": email}
|
result = {"vip": True, "email": email}
|
||||||
|
if linked_user_id:
|
||||||
|
result["linked_user_id"] = linked_user_id
|
||||||
_cache_set(cache_key, result)
|
_cache_set(cache_key, result)
|
||||||
return result
|
return result
|
||||||
except Exception as error:
|
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
|
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:
|
def _pb_get_user_by_id(admin_token: str, user_id: str) -> dict | None:
|
||||||
base = (PB_URL or "").rstrip("/")
|
base = (PB_URL or "").rstrip("/")
|
||||||
response = _http_session.get(
|
response = _http_session.get(
|
||||||
@@ -493,11 +604,21 @@ async def nomadvip_wechat_profile(item: dict):
|
|||||||
)
|
)
|
||||||
if email and effective_member_user_id:
|
if email and effective_member_user_id:
|
||||||
try:
|
try:
|
||||||
|
# 保持历史语义:vip_email_link.anonymous_user_id 仍仅承载历史业务 user_id
|
||||||
|
link_anonymous_id = anonymous_user_id or None
|
||||||
_pb_upsert_email_link(
|
_pb_upsert_email_link(
|
||||||
admin_token,
|
admin_token,
|
||||||
email,
|
email,
|
||||||
effective_member_user_id,
|
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:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@@ -1124,6 +1245,7 @@ async def nomadvip_check_vip_by_email(item: dict):
|
|||||||
anonymous_user_id = (
|
anonymous_user_id = (
|
||||||
item.get("user_id") or item.get("anonymousUserId") or ""
|
item.get("user_id") or item.get("anonymousUserId") or ""
|
||||||
).strip()
|
).strip()
|
||||||
|
wechat_userid = (item.get("wechat_userid") or item.get("userid") or "").strip()
|
||||||
logging.info(
|
logging.info(
|
||||||
"[payjsapi] check_vip_by_email email=%s user_id=%s",
|
"[payjsapi] check_vip_by_email email=%s user_id=%s",
|
||||||
email or "(empty)",
|
email or "(empty)",
|
||||||
@@ -1132,7 +1254,7 @@ async def nomadvip_check_vip_by_email(item: dict):
|
|||||||
|
|
||||||
if not email or not password:
|
if not email or not password:
|
||||||
return {"vip": False, "error": "missing email or 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)
|
cached = _cache_get(cache_key)
|
||||||
if cached is not None:
|
if cached is not None:
|
||||||
return cached
|
return cached
|
||||||
@@ -1175,11 +1297,8 @@ async def nomadvip_check_vip_by_email(item: dict):
|
|||||||
pb = get_pb_client()
|
pb = get_pb_client()
|
||||||
matched_user_id = None
|
matched_user_id = None
|
||||||
vip_check_cache: dict[str, bool] = {}
|
vip_check_cache: dict[str, bool] = {}
|
||||||
recovered_anonymous_user_id = (
|
# 保持历史语义:匿名ID只来自历史 user_id,不使用真实 wechat userid 覆盖
|
||||||
anonymous_user_id
|
recovered_anonymous_user_id = (anonymous_user_id or None)
|
||||||
if anonymous_user_id.startswith("user") and anonymous_user_id[4:].isdigit()
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
recovery_source = None
|
recovery_source = None
|
||||||
|
|
||||||
def has_vip_cached(uid: str) -> bool:
|
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):
|
if not has_vip_cached(linked_uid):
|
||||||
continue
|
continue
|
||||||
matched_user_id = linked_uid
|
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
|
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
|
recovered_anonymous_user_id = linked_uid
|
||||||
recovery_source = "vip_email_link"
|
recovery_source = "vip_email_link"
|
||||||
break
|
break
|
||||||
@@ -1250,6 +1369,14 @@ async def nomadvip_check_vip_by_email(item: dict):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
_pb_upsert_email_link(admin_token, email, pb_user_id)
|
_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(
|
logging.info(
|
||||||
"[payjsapi] check_vip_by_email recovered by %s matched_user_id=%s effectiveUserId=%s anonymousUserId=%s",
|
"[payjsapi] check_vip_by_email recovered by %s matched_user_id=%s effectiveUserId=%s anonymousUserId=%s",
|
||||||
|
|||||||
Reference in New Issue
Block a user