Files
Django/jituan/services/club_resolver.py

162 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""俱乐部微信配置与 openid 解析。"""
import logging
import re
import requests
from django.conf import settings
from jituan.constants import CLUB_ID_DEFAULT
from jituan.models import Club
logger = logging.getLogger(__name__)
_REFERER_APPID_RE = re.compile(r'servicewechat\.com/(wx[0-9a-fA-F]+)/', re.I)
def resolve_club_by_appid(app_id):
if not app_id:
return None
try:
return Club.query.filter(wx_appid=app_id, status=1).first()
except Exception:
return Club.objects.filter(wx_appid=app_id, status=1).first()
def get_club_wx_credentials(club_id):
"""优先读 club 表xq 缺省时回退 settings 全局配置(兼容现网)。"""
club_id = club_id or CLUB_ID_DEFAULT
try:
club = Club.query.get(club_id=club_id)
except Club.DoesNotExist:
club = None
if club and club.wx_appid and club.wx_secret:
return club.wx_appid, club.wx_secret, club
if club_id == CLUB_ID_DEFAULT:
return (
getattr(settings, 'WEIXIN_APPID', ''),
getattr(settings, 'WEIXIN_SECRET', ''),
club,
)
return '', '', club
def _invite_code_from_request(request):
data = getattr(request, 'data', None) or {}
if not isinstance(data, dict):
return ''
return (data.get('inviteCode') or data.get('invite_code') or '').strip()
def resolve_club_from_invite_code(invite_code):
"""老端无 Header/Referer 时,从管事邀请码反查俱乐部。"""
invite_code = (invite_code or '').strip()
if not invite_code:
return None
try:
from users.models import UserGuanshi
from jituan.services.club_user import resolve_invite_party_club
guanshi = UserGuanshi.query.select_related('user').get(yaoqingma=invite_code)
user = guanshi.user
club = resolve_invite_party_club(user, None)
if club:
return club
explicit = (getattr(user, 'ClubID', None) or '').strip()
return explicit or None
except Exception:
return None
def resolve_club_id_for_wechat_request(request):
"""
小程序请求解析 club_id登录/扫码注册)。
优先级X-Club-Id > body.appId > Referer > body.inviteCode 反查管事 > JWT 用户归属 > 默认 xq。
老端 fighter.js 的 wdlyhdl 未带头时,靠 Referer 或邀请码识别星之界。
"""
from jituan.services.club_context import resolve_club_id_from_request
header = (request.META.get('HTTP_X_CLUB_ID') or '').strip()
if not header and hasattr(request, 'headers'):
header = (request.headers.get('X-Club-Id') or '').strip()
if header:
return header
app_id = ''
data = getattr(request, 'data', None) or {}
if isinstance(data, dict):
app_id = (data.get('appId') or data.get('app_id') or '').strip()
if not app_id:
referer = request.META.get('HTTP_REFERER', '') or ''
matched = _REFERER_APPID_RE.search(referer)
if matched:
app_id = matched.group(1)
if app_id:
club = resolve_club_by_appid(app_id)
if club:
return club.club_id
invite_club = resolve_club_from_invite_code(_invite_code_from_request(request))
if invite_club:
return invite_club
# 已登录走 dashouzhuce 时往往无 Referer用 JWT 用户归属俱乐部
user = getattr(request, 'user', None)
if user is not None and getattr(user, 'is_authenticated', False):
from jituan.services.club_user import get_user_club_id
user_club = get_user_club_id(user)
if user_club:
return user_club
return resolve_club_id_from_request(request)
def wechat_jscode2session_for_request(request, code):
"""按请求上下文换取 openid多俱乐部小程序"""
club_id = resolve_club_id_for_wechat_request(request)
return jscode2session(code, club_id=club_id)
def jscode2session(code, club_id=None, app_id=None):
"""
按俱乐部微信配置换取 openid。
club_id 与 app_id 二选一app_id 用于从小程序 appId 反查 club。
"""
club = None
if app_id:
club = resolve_club_by_appid(app_id)
club_id = club.club_id if club else club_id
appid, secret, club = get_club_wx_credentials(club_id)
if not appid or not secret:
return {'errmsg': '俱乐部微信配置未设置'}
url = 'https://api.weixin.qq.com/sns/jscode2session'
params = {
'appid': appid,
'secret': secret,
'js_code': code,
'grant_type': 'authorization_code',
}
try:
response = requests.get(url, params=params, timeout=10)
result = response.json()
if 'openid' in result:
return {
'openid': result['openid'],
'session_key': result.get('session_key', ''),
'unionid': result.get('unionid', ''),
'club_id': club_id or CLUB_ID_DEFAULT,
'wx_appid': appid,
}
errcode = result.get('errcode', 'unknown')
errmsg = result.get('errmsg', '未知错误')
return {'errmsg': f'[{errcode}]{errmsg}'}
except requests.exceptions.Timeout:
return {'errmsg': '请求微信接口超时'}
except Exception as e:
logger.exception('jscode2session 异常 club_id=%s', club_id)
return {'errmsg': f'请求微信接口异常: {str(e)}'}