fix: 打手登录先认身份,默认邀请码改由后端下发
This commit is contained in:
47
jituan/services/default_invite.py
Normal file
47
jituan/services/default_invite.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""俱乐部默认打手邀请码(一键登录无扫码时使用)。"""
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CONFIG_KEY = 'default_dashou_invite'
|
||||
|
||||
# 与 club_migrate.CLUB_MIGRATE_DEFAULT_GUANSHI_INVITE 保持同步(无 config_json 时回落)
|
||||
_FALLBACK_DEFAULT_INVITE = {
|
||||
'lxs': '0000008VfJKPu4Spmcjt',
|
||||
'xq': '0000008RffVgKHMj7kQC',
|
||||
}
|
||||
|
||||
|
||||
def get_club_default_dashou_invite(club_id: str) -> str:
|
||||
"""
|
||||
优先读 Club.config_json.default_dashou_invite,
|
||||
否则回落内置各店默认管事邀请码。
|
||||
"""
|
||||
cid = (club_id or '').strip()
|
||||
if not cid:
|
||||
return ''
|
||||
try:
|
||||
from jituan.models import Club
|
||||
club = Club.query.filter(club_id=cid).first()
|
||||
if club:
|
||||
cfg = club.config_json or {}
|
||||
code = (cfg.get(CONFIG_KEY) or '').strip()
|
||||
if code:
|
||||
return code
|
||||
except Exception:
|
||||
logger.exception('read default_dashou_invite failed club=%s', cid)
|
||||
try:
|
||||
from jituan.services.club_migrate import CLUB_MIGRATE_DEFAULT_GUANSHI_INVITE
|
||||
code = (CLUB_MIGRATE_DEFAULT_GUANSHI_INVITE.get(cid) or '').strip()
|
||||
if code:
|
||||
return code
|
||||
except Exception:
|
||||
pass
|
||||
return (_FALLBACK_DEFAULT_INVITE.get(cid) or '').strip()
|
||||
|
||||
|
||||
def set_club_default_dashou_invite(club, invite_code: str) -> None:
|
||||
"""写入 club.config_json,调用方负责 save。"""
|
||||
cfg = dict(getattr(club, 'config_json', None) or {})
|
||||
cfg[CONFIG_KEY] = (invite_code or '').strip()
|
||||
club.config_json = cfg
|
||||
@@ -52,6 +52,7 @@ from jituan.views import (
|
||||
ClubKefuMenuAccessView,
|
||||
ClubPermDebugView,
|
||||
ClubListView,
|
||||
ClubDefaultInviteView,
|
||||
ClubMeContextView,
|
||||
ClubOrderFinanceView,
|
||||
ClubOrderTypesView,
|
||||
@@ -227,4 +228,5 @@ urlpatterns = [
|
||||
path('houtai/dashou-exam-question-manage', DashouExamQuestionManageView.as_view(), name='jituan_dashou_exam_q_manage'),
|
||||
path('houtai/dashou-exam-image-manage', DashouExamImageManageView.as_view(), name='jituan_dashou_exam_img'),
|
||||
path('club/list', ClubListView.as_view(), name='jituan_club_list'),
|
||||
path('club/default-invite', ClubDefaultInviteView.as_view(), name='jituan_club_default_invite'),
|
||||
]
|
||||
|
||||
@@ -285,6 +285,37 @@ class ClubListView(APIView):
|
||||
return Response({'code': 0, 'msg': 'ok', 'data': data})
|
||||
|
||||
|
||||
class ClubDefaultInviteView(APIView):
|
||||
"""
|
||||
GET/POST /jituan/club/default-invite
|
||||
小程序登录页拉取当前俱乐部默认打手邀请码(AllowAny)。
|
||||
俱乐部由 X-Club-Id / AppID 解析;码来自 config_json.default_dashou_invite 或内置回落。
|
||||
"""
|
||||
permission_classes = [AllowAny]
|
||||
throttle_classes = [AnonRateThrottle]
|
||||
|
||||
def _payload(self, request):
|
||||
from jituan.services.club_resolver import resolve_club_id_for_wechat_request
|
||||
from jituan.services.default_invite import get_club_default_dashou_invite
|
||||
|
||||
club_id = resolve_club_id_for_wechat_request(request)
|
||||
invite = get_club_default_dashou_invite(club_id)
|
||||
return Response({
|
||||
'code': 0,
|
||||
'msg': 'ok',
|
||||
'data': {
|
||||
'club_id': club_id or '',
|
||||
'inviteCode': invite,
|
||||
},
|
||||
})
|
||||
|
||||
def get(self, request):
|
||||
return self._payload(request)
|
||||
|
||||
def post(self, request):
|
||||
return self._payload(request)
|
||||
|
||||
|
||||
class ClubMeContextView(APIView):
|
||||
"""GET /jituan/auth/me-context — 已登录客服刷新俱乐部上下文。"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
@@ -600,6 +631,9 @@ class ClubManageView(APIView):
|
||||
}
|
||||
|
||||
def _serialize(self, club, full=False):
|
||||
from jituan.services.default_invite import get_club_default_dashou_invite
|
||||
|
||||
cfg_json = club.config_json or {}
|
||||
base = {
|
||||
'club_id': club.club_id,
|
||||
'name': club.name,
|
||||
@@ -614,6 +648,7 @@ class ClubManageView(APIView):
|
||||
'goeasy_appkey': club.goeasy_appkey,
|
||||
'template_id': club.template_id,
|
||||
'sort_order': club.sort_order,
|
||||
'default_dashou_invite': get_club_default_dashou_invite(club.club_id),
|
||||
}
|
||||
if full:
|
||||
mch_key = self._effective_mch_key(club)
|
||||
@@ -633,6 +668,7 @@ class ClubManageView(APIView):
|
||||
'encoding_aes_key': club.encoding_aes_key,
|
||||
'goeasy_secret': club.goeasy_secret,
|
||||
'template_max_per_minute': club.template_max_per_minute,
|
||||
'default_dashou_invite_raw': (cfg_json.get('default_dashou_invite') or '').strip(),
|
||||
})
|
||||
return base
|
||||
|
||||
@@ -683,6 +719,11 @@ class ClubManageView(APIView):
|
||||
self._sync_mch_key_to_config_json(club, request.data.get('mch_key'))
|
||||
if 'config_json' not in update_fields:
|
||||
update_fields.append('config_json')
|
||||
if 'default_dashou_invite' in request.data:
|
||||
from jituan.services.default_invite import set_club_default_dashou_invite
|
||||
set_club_default_dashou_invite(club, request.data.get('default_dashou_invite'))
|
||||
if 'config_json' not in update_fields:
|
||||
update_fields.append('config_json')
|
||||
if update_fields:
|
||||
club.save(update_fields=update_fields)
|
||||
return Response({
|
||||
|
||||
@@ -512,12 +512,15 @@ class DashouZhuceView(APIView):
|
||||
def post(self, request):
|
||||
from jituan.services.api_compat import legacy_miniapp_error
|
||||
|
||||
# 1. 获取并验证邀请码参数
|
||||
yaoqingma = request.data.get('inviteCode')
|
||||
# 1. 获取并验证邀请码参数(空则用俱乐部默认码)
|
||||
yaoqingma = (request.data.get('inviteCode') or '').strip()
|
||||
if not yaoqingma:
|
||||
from jituan.services.club_resolver import resolve_club_id_for_wechat_request
|
||||
from jituan.services.default_invite import get_club_default_dashou_invite
|
||||
yaoqingma = get_club_default_dashou_invite(resolve_club_id_for_wechat_request(request))
|
||||
if not yaoqingma:
|
||||
return legacy_miniapp_error(400, '邀请码不能为空')
|
||||
|
||||
yaoqingma = yaoqingma.strip()
|
||||
if len(yaoqingma) > 100:
|
||||
return legacy_miniapp_error(400, '邀请码长度超过限制')
|
||||
|
||||
@@ -813,21 +816,21 @@ class WechatLoginAndDashouRegisterView(APIView):
|
||||
def post(self, request):
|
||||
"""
|
||||
处理微信登录并注册打手请求
|
||||
|
||||
顺序:先按 openid 认身份;已是打手则直接登录(不校验邀请码);
|
||||
仅新注册才要求邀请码(请求体 / 俱乐部默认码)。
|
||||
"""
|
||||
try:
|
||||
from jituan.services.api_compat import legacy_miniapp_error
|
||||
|
||||
# 1. 获取并验证参数
|
||||
# 1. 获取并验证参数(邀请码对新用户才强制)
|
||||
code = request.data.get('code', '').strip()
|
||||
yaoqingma = request.data.get('inviteCode', '').strip()
|
||||
|
||||
if not code:
|
||||
return legacy_miniapp_error(1, '微信授权码不能为空')
|
||||
|
||||
if not yaoqingma:
|
||||
return legacy_miniapp_error(2, '邀请码不能为空')
|
||||
|
||||
if len(yaoqingma) > 100:
|
||||
if yaoqingma and len(yaoqingma) > 100:
|
||||
return legacy_miniapp_error(3, '邀请码长度超过限制')
|
||||
|
||||
# 2. 获取微信openid(按俱乐部小程序 appid,勿用全局星阙配置)
|
||||
@@ -848,11 +851,11 @@ class WechatLoginAndDashouRegisterView(APIView):
|
||||
# 3. 获取客户端真实IP
|
||||
kehuduan_ip = self.huoquKehuduanIP(request)
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.services.club_user import (
|
||||
ensure_user_club_id,
|
||||
resolve_or_create_wx_user,
|
||||
)
|
||||
from jituan.services.default_invite import get_club_default_dashou_invite
|
||||
|
||||
# 4. 开始数据库事务(确保登录和注册的原子性)
|
||||
with transaction.atomic():
|
||||
@@ -870,16 +873,34 @@ class WechatLoginAndDashouRegisterView(APIView):
|
||||
user_main.UnionID = unionid
|
||||
user_main.save()
|
||||
|
||||
# 4.2 验证邀请码对应的管事(注册逻辑)
|
||||
ensure_user_club_id(user_main, club_id)
|
||||
|
||||
# 4.1 已是打手:直接登录,不校验邀请码
|
||||
dashou_exists = UserDashou.query.filter(user=user_main).exists()
|
||||
if dashou_exists:
|
||||
dashou_profile = UserDashou.query.get(user=user_main)
|
||||
if int(getattr(dashou_profile, 'zhanghaozhuangtai', 1) or 0) != 1:
|
||||
reason = (getattr(dashou_profile, 'fengjin_yuanyin', '') or '').strip()
|
||||
msg = '账号状态异常,您的账号已被封禁'
|
||||
if reason:
|
||||
msg = f'{msg}。原因:{reason}'
|
||||
else:
|
||||
msg = f'{msg},请联系客服'
|
||||
return legacy_miniapp_error(4031, msg)
|
||||
return self.fanhuiDengluZhuceshuju(user_main, dashou_profile)
|
||||
|
||||
# 4.2 新用户注册:邀请码优先用请求体,否则用俱乐部默认码
|
||||
if not yaoqingma:
|
||||
yaoqingma = get_club_default_dashou_invite(club_id)
|
||||
if not yaoqingma:
|
||||
return legacy_miniapp_error(2, '邀请码不能为空')
|
||||
|
||||
try:
|
||||
# 使用select_related获取管事及其关联的主表用户信息
|
||||
guanshi_profile = UserGuanshi.query.select_related('user').get(yaoqingma=yaoqingma)
|
||||
except UserGuanshi.DoesNotExist:
|
||||
ensure_user_club_id(user_main, club_id)
|
||||
return legacy_miniapp_error(404, '邀请码无效或不存在')
|
||||
|
||||
from jituan.services.invite_guard import assert_invite_same_club
|
||||
from jituan.services.club_resolver import resolve_club_id_for_wechat_request
|
||||
from jituan.services.club_user import resolve_invite_party_club
|
||||
|
||||
ok, invite_msg = assert_invite_same_club(
|
||||
@@ -895,27 +916,7 @@ class WechatLoginAndDashouRegisterView(APIView):
|
||||
)
|
||||
return legacy_miniapp_error(403, invite_msg)
|
||||
|
||||
ensure_user_club_id(user_main, resolve_club_id_for_wechat_request(request))
|
||||
|
||||
# 验证管事状态
|
||||
|
||||
# 4.3 检查用户是否已是打手
|
||||
dashou_exists = UserDashou.query.filter(user=user_main).exists()
|
||||
if dashou_exists:
|
||||
# 用户已是打手,直接返回信息
|
||||
dashou_profile = UserDashou.query.get(user=user_main)
|
||||
# 账号封禁:禁止登录发 token,前端进入登录页提示
|
||||
if int(getattr(dashou_profile, 'zhanghaozhuangtai', 1) or 0) != 1:
|
||||
reason = (getattr(dashou_profile, 'fengjin_yuanyin', '') or '').strip()
|
||||
msg = '账号状态异常,您的账号已被封禁'
|
||||
if reason:
|
||||
msg = f'{msg}。原因:{reason}'
|
||||
else:
|
||||
msg = f'{msg},请联系客服'
|
||||
return legacy_miniapp_error(4031, msg)
|
||||
return self.fanhuiDengluZhuceshuju(user_main, dashou_profile)
|
||||
|
||||
# 4.4 核心:为用户创建所有身份(打手、商家、管事)
|
||||
# 4.3 创建打手身份
|
||||
guanshi_yonghuid = guanshi_profile.user.UserUID
|
||||
|
||||
# 创建打手扩展表
|
||||
@@ -1143,10 +1144,16 @@ class WechatLoginAndDashouRegisterView(APIView):
|
||||
except UserBoss.DoesNotExist:
|
||||
pass
|
||||
|
||||
# 检查各身份状态(已是打手 ≠ 已是商家/管事,必须按表真实查询)
|
||||
# 检查各身份状态(已是打手 ≠ 已是商家/管事/组长,必须按表真实查询)
|
||||
dashou_status = 1
|
||||
shangjia_status = 1 if UserShangjia.query.filter(user=user_main).exists() else 0
|
||||
guanshi_status = 1 if UserGuanshi.query.filter(user=user_main).exists() else 0
|
||||
zuzhang_status = 0
|
||||
try:
|
||||
zz = UserZuzhang.query.filter(user=user_main).first()
|
||||
zuzhang_status = 1 if zz and int(getattr(zz, 'zhuangtai', 0) or 0) == 1 else 0
|
||||
except Exception:
|
||||
zuzhang_status = 0
|
||||
|
||||
# 生成token
|
||||
refresh = RefreshToken.for_user(user_main)
|
||||
@@ -1167,6 +1174,7 @@ class WechatLoginAndDashouRegisterView(APIView):
|
||||
'shangjiastatus': shangjia_status,
|
||||
'dashoustatus': dashou_status,
|
||||
'guanshistatus': guanshi_status,
|
||||
'zuzhangstatus': zuzhang_status,
|
||||
'dashouqun': group_info.get('dashouqun', ''),
|
||||
'dashouqunid': group_info.get('dashouqunid', ''),
|
||||
'guanshiqun': group_info.get('guanshiqun', ''),
|
||||
|
||||
Reference in New Issue
Block a user