fix: 邀请码俱乐部不符时提示两侧 club_id;新增 diagnose_lsx_invite 对齐种子
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
127
jituan/management/commands/diagnose_lsx_invite.py
Normal file
127
jituan/management/commands/diagnose_lsx_invite.py
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
"""诊断 / 对齐龙先生邀请种子与小程序 club_id。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
python manage.py diagnose_lsx_invite
|
||||||
|
python manage.py diagnose_lsx_invite --align-to lsx
|
||||||
|
python manage.py diagnose_lsx_invite --align-to-appid
|
||||||
|
"""
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from jituan.models import Club
|
||||||
|
from users.business_models import User
|
||||||
|
from users.models import UserGuanshi, UserZuzhang
|
||||||
|
|
||||||
|
LSX_APPID = 'wx7ff90e9d024fcdb8'
|
||||||
|
SEED_UIDS = ('9910001', '9910002')
|
||||||
|
FRONTEND_EXPECT = 'lsx'
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = '诊断龙先生种子邀请人 ClubID 与小程序是否一致,并可对齐'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--align-to',
|
||||||
|
type=str,
|
||||||
|
default='',
|
||||||
|
help='把种子用户 ClubID 改成指定值(如 lsx)',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--align-to-appid',
|
||||||
|
action='store_true',
|
||||||
|
help='按 wx_appid=龙先生 找到俱乐部,把种子 ClubID 对齐过去',
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
self.stdout.write(self.style.SUCCESS('=' * 60))
|
||||||
|
self.stdout.write('前端龙先生小程序默认 X-Club-Id / CLUB_ID = lsx')
|
||||||
|
self.stdout.write(f'龙先生 AppID = {LSX_APPID}')
|
||||||
|
self.stdout.write('')
|
||||||
|
|
||||||
|
clubs = list(Club.query.order_by('club_id'))
|
||||||
|
self.stdout.write(f'库里俱乐部 {len(clubs)} 个:')
|
||||||
|
target_by_app = None
|
||||||
|
for c in clubs:
|
||||||
|
mark = ''
|
||||||
|
if c.club_id == FRONTEND_EXPECT:
|
||||||
|
mark = ' ← 前端期望'
|
||||||
|
if (c.wx_appid or '') == LSX_APPID:
|
||||||
|
mark += ' ← AppID命中'
|
||||||
|
target_by_app = c
|
||||||
|
if '龙先生' in (c.name or ''):
|
||||||
|
mark += ' ← 名称命中'
|
||||||
|
self.stdout.write(
|
||||||
|
f' club_id={c.club_id!r} name={c.name!r} wx_appid={c.wx_appid or "(空)"}{mark}'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.stdout.write('')
|
||||||
|
self.stdout.write('种子用户:')
|
||||||
|
for uid in SEED_UIDS:
|
||||||
|
user = User.query.filter(UserUID=uid).first()
|
||||||
|
if not user:
|
||||||
|
self.stdout.write(self.style.WARNING(f' {uid}: 不存在(还没跑 seed_lsx_invite_data?)'))
|
||||||
|
continue
|
||||||
|
role = []
|
||||||
|
try:
|
||||||
|
z = user.ZuzhangProfile
|
||||||
|
role.append(f'组长码={z.yaoqingma}')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
g = user.GuanshiProfile
|
||||||
|
role.append(f'管事码={g.yaoqingma}')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
club = (user.ClubID or '').strip()
|
||||||
|
ok = club == FRONTEND_EXPECT
|
||||||
|
line = f' {uid}: ClubID={club or "(空)"} {" | ".join(role) or "无身份"}'
|
||||||
|
if ok:
|
||||||
|
self.stdout.write(self.style.SUCCESS(line + ' ✓ 与前端 lsx 一致'))
|
||||||
|
else:
|
||||||
|
self.stdout.write(self.style.ERROR(
|
||||||
|
line + f' ✗ 与前端 lsx 不一致 → 会报「邀请码不属于当前小程序俱乐部」'
|
||||||
|
))
|
||||||
|
|
||||||
|
self.stdout.write('')
|
||||||
|
self.stdout.write(self.style.WARNING(
|
||||||
|
'结论:这是后端校验(invite_guard),不是前端邀请码输错。\n'
|
||||||
|
'小程序发 X-Club-Id=lsx,邀请人 User.ClubID 必须也是 lsx。'
|
||||||
|
))
|
||||||
|
|
||||||
|
align_to = (options.get('align_to') or '').strip()
|
||||||
|
if options.get('align_to_appid'):
|
||||||
|
if not target_by_app:
|
||||||
|
raise CommandError(f'没有 wx_appid={LSX_APPID} 的俱乐部,无法对齐')
|
||||||
|
align_to = target_by_app.club_id
|
||||||
|
self.stdout.write(f'将按 AppID 对齐到 club_id={align_to!r}')
|
||||||
|
|
||||||
|
if not align_to:
|
||||||
|
self.stdout.write('')
|
||||||
|
self.stdout.write('若要修复,任选其一:')
|
||||||
|
self.stdout.write(' python manage.py diagnose_lsx_invite --align-to lsx')
|
||||||
|
self.stdout.write(' python manage.py diagnose_lsx_invite --align-to-appid')
|
||||||
|
self.stdout.write('然后前端 CLUB_ID 必须与种子 ClubID 相同。')
|
||||||
|
self.stdout.write(self.style.SUCCESS('=' * 60))
|
||||||
|
return
|
||||||
|
|
||||||
|
if not Club.query.filter(club_id=align_to).exists():
|
||||||
|
raise CommandError(f'目标俱乐部 {align_to!r} 不存在,请先在后台创建')
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
for uid in SEED_UIDS:
|
||||||
|
user = User.query.filter(UserUID=uid).first()
|
||||||
|
if not user:
|
||||||
|
self.stdout.write(self.style.WARNING(f'跳过不存在用户 {uid}'))
|
||||||
|
continue
|
||||||
|
old = user.ClubID
|
||||||
|
user.ClubID = align_to
|
||||||
|
user.save(update_fields=['ClubID'])
|
||||||
|
self.stdout.write(self.style.SUCCESS(
|
||||||
|
f'已更新 {uid}: ClubID {old!r} → {align_to!r}'
|
||||||
|
))
|
||||||
|
|
||||||
|
self.stdout.write(self.style.SUCCESS(
|
||||||
|
f'\n对齐完成。请确认小程序 config/club-config.js 的 CLUB_ID = {align_to!r}'
|
||||||
|
))
|
||||||
|
self.stdout.write(self.style.SUCCESS('=' * 60))
|
||||||
@@ -31,7 +31,11 @@ def assert_invite_same_club(request, inviter_user, invitee_user=None):
|
|||||||
'invite_guard 管事俱乐部不符 inviter=%s inviter_club=%s req_club=%s',
|
'invite_guard 管事俱乐部不符 inviter=%s inviter_club=%s req_club=%s',
|
||||||
getattr(inviter_user, 'UserUID', '?'), inviter_club, club_id,
|
getattr(inviter_user, 'UserUID', '?'), inviter_club, club_id,
|
||||||
)
|
)
|
||||||
return False, '邀请码不属于当前小程序俱乐部'
|
# 文案带上两侧 club,方便排查「种子 ClubID ≠ 小程序 X-Club-Id」
|
||||||
|
return False, (
|
||||||
|
f'邀请码不属于当前小程序俱乐部'
|
||||||
|
f'(邀请人归属={inviter_club or "空"},当前小程序={club_id or "空"})'
|
||||||
|
)
|
||||||
|
|
||||||
if invitee_user is not None:
|
if invitee_user is not None:
|
||||||
invitee_club = resolve_invite_party_club(invitee_user, club_id)
|
invitee_club = resolve_invite_party_club(invitee_user, club_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user