fix: 微信登录并发注册撞唯一键时正确回落已有用户
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
"""用户所属俱乐部解析。"""
|
||||
from django.db import IntegrityError
|
||||
from django.db import IntegrityError, transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.models import UserWxOpenid
|
||||
@@ -41,27 +41,52 @@ def resolve_invite_party_club(user, request_club_id=None):
|
||||
return None
|
||||
|
||||
|
||||
def find_user_by_wx_openid(club_id, openid):
|
||||
"""按俱乐部 openid 绑定或 legacy OpenID/UserName 定位用户。"""
|
||||
def _user_querysets():
|
||||
"""兼容 gvsdsdk User.query 与 Django User.objects。"""
|
||||
from users.business_models import User
|
||||
|
||||
if club_id and openid:
|
||||
seen = set()
|
||||
for qs in (getattr(User, 'objects', None), getattr(User, 'query', None)):
|
||||
if qs is None or id(qs) in seen:
|
||||
continue
|
||||
seen.add(id(qs))
|
||||
yield qs
|
||||
|
||||
|
||||
def find_user_by_wx_openid(club_id, openid):
|
||||
"""按俱乐部 openid 绑定或 legacy UserName/OpenID 定位用户。"""
|
||||
from users.business_models import User
|
||||
|
||||
openid = (openid or '').strip()
|
||||
if not openid:
|
||||
return None
|
||||
|
||||
if club_id:
|
||||
binding = UserWxOpenid.query.filter(club_id=club_id, openid=openid).first()
|
||||
if binding:
|
||||
user = User.query.filter(UserUID=binding.yonghuid).first()
|
||||
user = User.objects.filter(UserUID=binding.yonghuid).first()
|
||||
if not user:
|
||||
user = User.objects.filter(UserUID=binding.yonghuid).first()
|
||||
user = User.query.filter(UserUID=binding.yonghuid).first()
|
||||
if user:
|
||||
return user
|
||||
|
||||
user = User.query.filter(OpenID=openid).first()
|
||||
if not user:
|
||||
user = User.objects.filter(OpenID=openid).first()
|
||||
if not user:
|
||||
user = User.query.filter(UserName=openid).first()
|
||||
if not user:
|
||||
user = User.objects.filter(UserName=openid).first()
|
||||
return user
|
||||
binding_any = UserWxOpenid.query.filter(openid=openid).order_by('id').first()
|
||||
if binding_any:
|
||||
user = User.objects.filter(UserUID=binding_any.yonghuid).first()
|
||||
if not user:
|
||||
user = User.query.filter(UserUID=binding_any.yonghuid).first()
|
||||
if user:
|
||||
return user
|
||||
|
||||
# 星之界等用户常 UserName=openid 且 OpenID 为空,优先按 UserName 查
|
||||
for manager in _user_querysets():
|
||||
user = manager.filter(UserName=openid).first()
|
||||
if user:
|
||||
return user
|
||||
user = manager.filter(OpenID=openid).first()
|
||||
if user:
|
||||
return user
|
||||
return None
|
||||
|
||||
|
||||
def ensure_wx_openid_binding(club_id, openid, user, unionid=''):
|
||||
@@ -95,23 +120,29 @@ def resolve_or_create_wx_user(club_id, openid, generate_uid, unionid=''):
|
||||
import uuid
|
||||
from users.business_models import User
|
||||
|
||||
openid = (openid or '').strip()
|
||||
if not openid:
|
||||
raise ValueError('openid 不能为空')
|
||||
|
||||
user = find_user_by_wx_openid(club_id, openid)
|
||||
if user:
|
||||
ensure_wx_openid_binding(club_id, openid, user, unionid)
|
||||
return user, False
|
||||
|
||||
try:
|
||||
user = User(
|
||||
UserUUID=uuid.uuid4().bytes,
|
||||
UserUID=generate_uid(),
|
||||
UserName=openid,
|
||||
OpenID=openid if club_id == CLUB_ID_DEFAULT else None,
|
||||
UnionID=unionid or None,
|
||||
ClubID='',
|
||||
)
|
||||
user.save()
|
||||
ensure_wx_openid_binding(club_id, openid, user, unionid)
|
||||
return user, True
|
||||
# 嵌套 savepoint:并发注册撞唯一键时只回滚创建,不污染外层 atomic
|
||||
with transaction.atomic():
|
||||
user = User(
|
||||
UserUUID=uuid.uuid4().bytes,
|
||||
UserUID=generate_uid(),
|
||||
UserName=openid,
|
||||
OpenID=openid if club_id == CLUB_ID_DEFAULT else None,
|
||||
UnionID=unionid or None,
|
||||
ClubID='',
|
||||
)
|
||||
user.save()
|
||||
ensure_wx_openid_binding(club_id, openid, user, unionid)
|
||||
return user, True
|
||||
except IntegrityError:
|
||||
user = find_user_by_wx_openid(club_id, openid)
|
||||
if not user:
|
||||
|
||||
Reference in New Issue
Block a user