增加微信登录多账户功能

pull/37/head
nineven 3 years ago
parent 391e4987de
commit 63e09c1925
  1. 51
      fir_client/src/components/FirLogin.vue
  2. 2
      fir_client/vue.config.js
  3. 13
      fir_ser/api/management/commands/create_weixin_menu.py
  4. 25
      fir_ser/api/migrations/0005_auto_20220329_1131.py
  5. 7
      fir_ser/api/models.py
  6. 2
      fir_ser/api/urls.py
  7. 18
      fir_ser/api/utils/serializer.py
  8. 22
      fir_ser/api/views/getip.py
  9. 54
      fir_ser/api/views/login_wx.py
  10. 167
      fir_ser/api/views/thirdlogin.py
  11. 14
      fir_ser/common/base/baseutils.py
  12. 3
      fir_ser/common/core/sysconfig.py
  13. 34
      fir_ser/common/libs/mp/wechat.py
  14. 2
      fir_ser/common/notify/notify.py
  15. 16
      fir_ser/fir_ser/settings.py
  16. 12
      fir_ser/xsign/utils/iproxy.py
  17. 12
      fir_ser/xsign/utils/supersignutils.py
  18. 9
      fir_ser/xsign/views/supersign.py

@ -74,7 +74,29 @@
<div v-if="allow_ways.third && JSON.stringify(allow_ways.third).indexOf('true')!==-1" class="other-way">
<hr>
<span class="info">或使用以下账户登录</span>
<el-popover
placement="top"
title="该微信绑定了多个用户,请选择账户,并点击登录"
width="400"
trigger="manual"
v-model="showuserlist">
<el-row style="margin-top: 20px">
<el-col v-for="userinfo in userinfo_list" :key="userinfo.uid" :span="8" style="margin-left: 40px">
<div @click="weixinlogin(userinfo)">
<el-card :body-style="{textAlign:'center',padding:'8px',width:'120px'}" shadow="hover" >
<!-- <el-image :src="userinfo.head_img"></el-image>-->
<el-avatar :src="userinfo.head_img" :size="100"></el-avatar>
<div style="margin: 5px 0 5px">
<span>{{ userinfo.first_name }}</span>
</div>
</el-card>
</div>
</el-col>
</el-row>
<span class="info" slot="reference">或使用以下账户登录</span>
</el-popover>
<el-popover
v-if="allow_ways.third && allow_ways.third.wxp"
@ -127,11 +149,28 @@ export default {
wx_login_qr_url: '',
wx_visible: false,
loop_flag: false,
unique_key: ''
unique_key: '',
userinfo_list:[],
unique_wid:'',
showuserlist:false
}
},
methods: {
weixinlogin(userinfo){
wxLoginFun(data=>{
if(data.code === 1000){
this.set_cookie_and_token(data);
}else if(data.code ===1005) {
this.$message.error(data.msg)
}else {
this.showuserlist=false
this.$message.error(data.msg)
}
},{
'methods':'PUT',
'data':{uid:userinfo.uid,token:userinfo.token,'wid':this.unique_wid}
})
},
set_cookie_and_token(data) {
this.$cookies.remove("auth_token");
this.$cookies.set("token", data['token'], 3600 * 24 * 30);
@ -168,6 +207,12 @@ export default {
this.loop_flag = false;
} else if (data.code === 1006) {
return this.loop_get_wx_info(wx_login_ticket, c_count, unique_key)
} else if (data.code === 2000){
this.wx_visible = false;
this.loop_flag = false;
this.userinfo_list = data.data;
this.unique_wid = data.wid;
this.showuserlist=true
}
}, {
"methods": "POST",

@ -82,7 +82,7 @@ if (page) {
}
}
const version='2.2.5';
const version='2.2.6';
const pro_base_env = {
baseUrl: 'https://flyapps.cn',

@ -0,0 +1,13 @@
from django.core.management.base import BaseCommand
from common.libs.mp.wechat import create_menu
class Command(BaseCommand):
help = 'create weixin menu'
def add_arguments(self, parser):
parser.add_argument('menu_json', nargs='?', type=str, default=None)
def handle(self, *args, **options):
create_menu(options.get('menu_json', None))

@ -0,0 +1,25 @@
# Generated by Django 3.2.3 on 2022-03-29 11:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0004_auto_20220326_1847'),
]
operations = [
migrations.AlterModelOptions(
name='thirdwechatuserinfo',
options={'verbose_name': '微信相关信息', 'verbose_name_plural': '微信相关信息'},
),
migrations.AlterField(
model_name='thirdwechatuserinfo',
name='openid',
field=models.CharField(max_length=64, verbose_name='普通用户的标识,对当前公众号唯一'),
),
migrations.AlterUniqueTogether(
name='thirdwechatuserinfo',
unique_together={('user_id', 'openid')},
),
]

@ -72,7 +72,7 @@ class UserInfo(AbstractUser):
class ThirdWeChatUserInfo(models.Model):
user_id = models.ForeignKey(to=UserInfo, verbose_name="用户ID", on_delete=models.CASCADE)
openid = models.CharField(max_length=64, unique=True, verbose_name="普通用户的标识,对当前公众号唯一")
openid = models.CharField(max_length=64, null=False, verbose_name="普通用户的标识,对当前公众号唯一")
nickname = models.CharField(max_length=64, verbose_name="昵称", blank=True)
sex = models.SmallIntegerField(default=0, verbose_name="性别", help_text="值为1时是男性,值为2时是女性,值为0时是未知")
subscribe_time = models.BigIntegerField(verbose_name="订阅时间")
@ -83,6 +83,11 @@ class ThirdWeChatUserInfo(models.Model):
enable_notify = models.BooleanField(verbose_name="是否允许推送消息", default=0)
created_time = models.DateTimeField(auto_now_add=True, verbose_name="授权时间")
class Meta:
verbose_name = '微信相关信息'
verbose_name_plural = "微信相关信息"
unique_together = (('user_id', 'openid'),)
def __str__(self):
return f"{self.user_id}-{self.nickname}-{self.openid}"

@ -19,6 +19,7 @@ from api.views.advert import UserAdInfoView
from api.views.apps import AppsView, AppInfoView, AppReleaseInfoView, AppsQrcodeShowView
from api.views.domain import DomainCnameView, DomainInfoView
from api.views.download import ShortDownloadView, InstallView, DownloadView
from api.views.getip import GetRemoteIp
from api.views.login import LoginView, UserInfoView, RegistView, AuthorizationView, ChangeAuthorizationView, \
UserApiTokenView, CertificationView, ChangeInfoView
from api.views.login_wx import WeChatLoginView, WeChatLoginCheckView, WeChatBindView, WeChatWebLoginView
@ -35,6 +36,7 @@ from api.views.uploads import AppAnalyseView, UploadView
urlpatterns = [
# path("",include(router.urls)),
re_path("^rip", GetRemoteIp.as_view()),
re_path("^login", LoginView.as_view()),
re_path("^auth$", AuthorizationView.as_view()),
re_path("^authc$", ChangeAuthorizationView.as_view()),

@ -6,7 +6,7 @@ from rest_framework import serializers
from api import models
from api.utils.apputils import bytes2human
from api.utils.modelutils import get_user_domain_name, get_app_domain_name, get_app_download_uri
from common.base.baseutils import get_choices_dict
from common.base.baseutils import get_choices_dict, WeixinLoginUid
from common.cache.storage import AdPicShowCache
from common.utils.caches import get_user_free_download_times, get_user_cert_auth_status
from common.utils.storage import Storage
@ -94,6 +94,22 @@ class UserInfoSerializer(serializers.ModelSerializer):
return get_user_domain_name(obj, 0)
class UserInfoWeiXinSerializer(UserInfoSerializer):
class Meta:
model = models.UserInfo
fields = ["uid", "first_name", 'head_img', 'storage_active', 'token']
uid = serializers.SerializerMethodField()
token = serializers.SerializerMethodField()
def get_uid(self, obj):
return WeixinLoginUid().get_encrypt_uid(obj.uid)
def get_token(self, obj):
access_token = make_token(obj.uid, 600, key=self.context.get('ticket', 'weixin_login'), force_new=True)
return access_token
class AppsSerializer(serializers.ModelSerializer):
class Meta:
model = models.Apps

@ -0,0 +1,22 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: fir_ser
# filename: getip
# author: liuyu
# data: 2022/3/28
import logging
from rest_framework.response import Response
from rest_framework.views import APIView
from common.base.baseutils import get_real_ip_address
logger = logging.getLogger(__name__)
class GetRemoteIp(APIView):
def get(self, request):
logger.info(f"real_ip:{get_real_ip_address(request)}")
return Response({'real_ip': get_real_ip_address(request)})

@ -6,16 +6,17 @@ from rest_framework.views import APIView
from api.models import UserInfo, ThirdWeChatUserInfo
from api.utils.response import BaseResponse
from api.utils.serializer import UserInfoSerializer
from api.utils.serializer import UserInfoSerializer, UserInfoWeiXinSerializer
from api.utils.utils import set_user_token
from common.base.baseutils import get_real_ip_address
from common.base.baseutils import get_real_ip_address, WeixinLoginUid
from common.cache.storage import WxLoginBindCache
from common.core.auth import ExpiringTokenAuthentication
from common.core.sysconfig import Config
from common.core.throttle import VisitRegister1Throttle, VisitRegister2Throttle
from common.libs.mp.wechat import make_wx_login_qrcode, show_qrcode_url, WxWebLogin
from common.libs.mp.wechat import make_wx_login_qrcode, show_qrcode_url, WxWebLogin, WxTemplateMsg
from common.utils.caches import set_wx_ticket_login_info_cache, get_wx_ticket_login_info_cache
from common.utils.pending import get_pending_result
from common.utils.token import verify_token
logger = logging.getLogger(__name__)
@ -56,6 +57,43 @@ class WeChatLoginView(APIView):
return wx_qr_code_response(ret, code, qr_info, get_real_ip_address(request))
return Response(ret.dict)
def put(self, request):
ret = BaseResponse()
data = request.data
token = data.get('token')
uid = data.get('uid')
wid = data.get('wid')
if token and uid and wid:
uid = WeixinLoginUid().get_decrypt_uid(uid)
wid = WeixinLoginUid().get_decrypt_uid(wid)
if verify_token(token, uid, True):
user = UserInfo.objects.filter(uid=uid).first()
if user and user.is_active:
wx_user_obj = ThirdWeChatUserInfo.objects.filter(openid=wid, enable_login=True,
user_id=user).first()
if wx_user_obj:
key, user_info = set_user_token(user, request)
serializer = UserInfoSerializer(user_info)
data = serializer.data
ret.userinfo = data
ret.token = key
ret.msg = "验证成功!"
WxTemplateMsg(wid, wx_user_obj.nickname).login_success_msg(user.first_name)
else:
ret.msg = "微信状态异常,请重新登录"
ret.code = 1006
else:
ret.msg = "用户被禁用,请更换其他用户登录"
ret.code = 1005
else:
ret.msg = "校验失败,请重新登录"
ret.code = 1006
else:
ret.msg = "参数异常,请重新登录"
ret.code = 1006
return Response(ret.dict)
class WeChatBindView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
@ -102,8 +140,18 @@ class WeChatLoginCheckView(APIView):
ret.msg = "还未绑定用户,请通过手机或者邮箱登录账户之后进行绑定"
ret.code = 1005
else:
ids = wx_ticket_data.get('ids', [])
w_type = wx_ticket_data.get('w_type', '')
to_user = wx_ticket_data.get('to_user', '')
if ids:
user_queryset = UserInfo.objects.filter(pk__in=ids, is_active=True).all()
if user_queryset:
ret.data = UserInfoWeiXinSerializer(user_queryset, many=True,
context={'ticket': ticket}).data
ret.wid = WeixinLoginUid().get_encrypt_uid(to_user)
ret.code = 2000
return Response(ret.dict)
user = UserInfo.objects.filter(pk=wx_ticket_data['pk']).first()
wx_obj = ThirdWeChatUserInfo.objects.filter(user_id=user, openid=to_user,
enable_login=True).filter()

@ -46,23 +46,30 @@ class TextXMLParser(XMLParser):
def reply_login_msg(rec_msg, to_user, from_user):
content = f'还未绑定用户,请通过手机或者邮箱登录账户之后进行绑定'
u_data_id = -1
wx_user_obj = ThirdWeChatUserInfo.objects.filter(openid=to_user, enable_login=True).first()
ids = []
wx_user_obj_queryset = ThirdWeChatUserInfo.objects.filter(openid=to_user, enable_login=True).all()
wx_ticket_info = get_wx_ticket_login_info_cache(rec_msg.Ticket)
if wx_user_obj:
u_data_id = wx_user_obj.user_id.pk
content = f'用户 {wx_user_obj.user_id.first_name} 登录成功'
WxTemplateMsg(to_user, wx_user_obj.nickname).login_success_msg(wx_user_obj.user_id.first_name)
else:
wx_user_info = update_or_create_wx_userinfo(to_user)
WxTemplateMsg(to_user, wx_user_info.get('nickname', '')).login_failed_msg()
wx_user_count = wx_user_obj_queryset.count()
if 0 <= wx_user_count <= 1:
wx_user_obj = wx_user_obj_queryset.first()
if wx_user_obj:
u_data_id = wx_user_obj.user_id.pk
content = f'用户 {wx_user_obj.user_id.first_name} 登录成功'
WxTemplateMsg(to_user, wx_user_obj.nickname).login_success_msg(wx_user_obj.user_id.first_name)
else:
wx_user_info = update_or_create_wx_userinfo(to_user)
WxTemplateMsg(to_user, wx_user_info.get('nickname', '')).login_failed_msg()
elif wx_user_count > 1:
ids = [x['user_id__id'] for x in wx_user_obj_queryset.values('user_id__id')]
u_data_id = wx_user_obj_queryset.first().user_id.pk
content = f'您刚才进行了扫码登录,多用户登录中'
if wx_ticket_info and wx_ticket_info.get('ip_addr'):
ip_addr = wx_ticket_info.get('ip_addr')
logger.info(f"{content} ip:{ip_addr}")
set_wx_ticket_login_info_cache(rec_msg.Ticket, {'pk': u_data_id, 'to_user': to_user})
set_wx_ticket_login_info_cache(rec_msg.Ticket, {'pk': u_data_id, 'to_user': to_user, "ids": ids})
reply_msg = reply.TextMsg(to_user, from_user, content)
return reply_msg.send()
@ -93,8 +100,9 @@ def update_or_create_wx_userinfo(to_user, user_obj=None, w_type=''):
def wx_bind_utils(rec_msg, to_user, from_user, content):
w_type = rec_msg.Eventkey.split('.')[-1]
uid = rec_msg.Eventkey.split('.')[-2]
wx_user_obj = ThirdWeChatUserInfo.objects.filter(openid=to_user).first()
user_obj = UserInfo.objects.filter(uid=uid).first()
wx_user_obj = ThirdWeChatUserInfo.objects.filter(openid=to_user, user_id__uid=uid).first()
if wx_user_obj:
wx_template_msg_obj = WxTemplateMsg(to_user, wx_user_obj.nickname)
if user_obj and user_obj.uid == wx_user_obj.user_id.uid:
@ -133,11 +141,33 @@ class ValidWxChatToken(APIView):
if ret == 0:
content = '欢迎使用fly应用分发平台,感谢您的关注'
rec_msg = receive.parse_xml(encrypt_xml)
logger.info(f"code:{ret}, parse_xml result {rec_msg.__dict__ if rec_msg else rec_msg}")
if isinstance(rec_msg, receive.Msg):
to_user = rec_msg.FromUserName
from_user = rec_msg.ToUserName
if rec_msg.MsgType == 'text':
msg = rec_msg.Content.decode('utf-8')
if msg and (msg.startswith('解除登录绑定') or msg.startswith('解除消息绑定')):
msg_list = msg.split(' ')
if len(msg_list) == 2:
uid = msg_list[-1]
wx_user_obj = ThirdWeChatUserInfo.objects.filter(openid=to_user, user_id__uid=uid).first()
data = {}
w_msg = []
if msg.startswith('解除登录绑定'):
data.update({'enable_login': False})
w_msg.append('扫码登录')
if msg.startswith('解除消息绑定'):
w_msg.append('消息推送')
data.update({'enable_notify': False})
if data:
ThirdWeChatUserInfo.objects.filter(openid=to_user, user_id__uid=uid).update(**data)
WxTemplateMsg(to_user, wx_user_obj.nickname).unbind_success_msg(
wx_user_obj.user_id.first_name, f"{' '.join(w_msg)} 解绑成功",
"如需重新绑定,请登陆平台,进行绑定。感谢您的关注")
return HttpResponse("success")
content = random.choices([*GOOD_XX, content, rec_msg.Content.decode('utf-8')])[0]
reply_msg = reply.TextMsg(to_user, from_user, content)
result = reply_msg.send()
@ -165,56 +195,85 @@ class ValidWxChatToken(APIView):
result = reply_msg.send()
logger.info(f"replay msg: {result}")
return HttpResponse(result)
elif rec_msg.Eventkey in ['query_bind', 'unbind']:
wx_user_obj = ThirdWeChatUserInfo.objects.filter(openid=to_user).filter(
Q(enable_login=True) | Q(enable_notify=True)).first()
elif rec_msg.Eventkey in ['query_bind', 'unbind', 'unbind_all']:
wx_user_obj_queryset = ThirdWeChatUserInfo.objects.filter(openid=to_user).filter(
Q(enable_login=True) | Q(enable_notify=True)).all()
if rec_msg.Eventkey == 'query_bind':
if wx_user_obj:
user_obj = wx_user_obj.user_id
content = f'绑定用户 {user_obj.first_name} '
if user_obj.email:
content += f' 登录邮箱:{user_obj.email} '
if user_obj.mobile:
content += f' 登录手机:{user_obj.mobile}'
user_cert_obj = UserCertificationInfo.objects.filter(user_id=user_obj,
status=1).first()
if user_cert_obj:
name = user_cert_obj.name
else:
name = user_obj.first_name
description = f'绑定了'
if wx_user_obj.enable_login:
description += " 微信登录 "
if wx_user_obj.enable_notify:
description += " 消息通知 "
description += "功能。"
WxTemplateMsg(to_user, wx_user_obj.nickname).bind_query_success_msg(user_obj.first_name,
name,
user_obj.mobile,
user_obj.email,
description)
else:
content = '暂无登录绑定信息'
for wx_user_obj in wx_user_obj_queryset:
if wx_user_obj:
user_obj = wx_user_obj.user_id
content = f'绑定用户 {user_obj.first_name} '
if user_obj.email:
content += f' 登录邮箱:{user_obj.email} '
if user_obj.mobile:
content += f' 登录手机:{user_obj.mobile}'
user_cert_obj = UserCertificationInfo.objects.filter(user_id=user_obj,
status=1).first()
if user_cert_obj:
name = user_cert_obj.name
else:
name = user_obj.first_name
description = f'绑定了'
if wx_user_obj.enable_login:
description += " 微信登录 "
if wx_user_obj.enable_notify:
description += " 消息通知 "
description += "功能。"
WxTemplateMsg(to_user, wx_user_obj.nickname).bind_query_success_msg(
user_obj.first_name,
name,
user_obj.mobile,
user_obj.email,
description)
if wx_user_obj_queryset.count() == 0:
content = '暂无绑定信息'
wx_user_info = update_or_create_wx_userinfo(to_user)
WxTemplateMsg(to_user, wx_user_info.get('nickname')).query_bind_info_failed_msg(
"查询登录绑定", content)
elif rec_msg.Eventkey == 'unbind':
if wx_user_obj:
content = f'解绑用户 {wx_user_obj.user_id.first_name} 成功'
WxTemplateMsg(to_user, wx_user_obj.nickname).unbind_success_msg(
wx_user_obj.user_id.first_name)
ThirdWeChatUserInfo.objects.filter(openid=to_user).delete()
else:
content = f'暂无登录绑定信息'
"查询绑定", content)
elif rec_msg.Eventkey == 'unbind_all':
for wx_user_obj in wx_user_obj_queryset:
if wx_user_obj:
content = f'解绑用户 {wx_user_obj.user_id.first_name} 成功'
WxTemplateMsg(to_user, wx_user_obj.nickname).unbind_success_msg(
wx_user_obj.user_id.first_name,
"解除绑定成功,您将无法使用微信扫描登录平台和微信消息推送功能",
"如需重新绑定,请登陆平台,在个人资料进行登录绑定。感谢您的关注")
ThirdWeChatUserInfo.objects.filter(openid=to_user).update(enable_login=False,
enable_notify=False)
if wx_user_obj_queryset.count() == 0:
content = f'暂无绑定信息'
wx_user_info = update_or_create_wx_userinfo(to_user)
WxTemplateMsg(to_user, wx_user_info.get('nickname')).query_bind_info_failed_msg(
"解除登录绑定", content)
"解除绑定", content)
elif rec_msg.Eventkey == 'unbind':
if wx_user_obj_queryset.count() == 0:
content = f'暂无绑定信息'
else:
content = ''
for wx_user_obj in wx_user_obj_queryset:
user_obj = wx_user_obj.user_id
user_content = f'用户昵称 {user_obj.first_name} '
if user_obj.email:
user_content += f' 登录邮箱:{user_obj.email} '
if user_obj.mobile:
user_content += f' 登录手机:{user_obj.mobile}'
content += f'{user_content}\n'
if wx_user_obj.enable_login:
login_info = f'解除登录绑定 {user_obj.uid}'
content += f'<a href="weixin://bizmsgmenu?msgmenuid=1&msgmenucontent={login_info}">【解除登录绑定】</a>'
if wx_user_obj.enable_notify:
notify_info = f'解除消息绑定 {user_obj.uid}'
content += f'<a href="weixin://bizmsgmenu?msgmenuid=1&msgmenucontent={notify_info}">【解除消息绑定】</a>'
content += '\n\n'
content += '请点击您要解除绑定的信息\n'
logger.info(f"to_user:{to_user} from_user:{from_user} reply msg: {content}")
reply_msg = reply.TextMsg(to_user, from_user, content)
result = reply_msg.send()
if rec_msg.Eventkey == 'unbind':
return HttpResponse(result)
elif rec_msg.Event in ['subscribe', 'unsubscribe']: # 订阅
reply_msg = reply.TextMsg(to_user, from_user, content)
@ -235,6 +294,8 @@ class ValidWxChatToken(APIView):
else:
logger.error('密文解密失败')
logger.info(f"replay msg: {result}")
# 直接回复修改为微信模板消息回复
# return HttpResponse(result)
return HttpResponse("success")

@ -56,18 +56,26 @@ class AESCipher(object):
return data
class AppleDeveloperUid(object):
class AesBaseCrypt(object):
def __init__(self):
self.cipher = AESCipher(self.__class__.__name__)
def get_encrypt_uid(self, raw):
return self.cipher.encrypt(raw.encode('utf-8')).decode('utf-8')
def get_encrypt_uid(self, key):
return self.cipher.encrypt(key.encode('utf-8')).decode('utf-8')
def get_decrypt_uid(self, enc):
return self.cipher.decrypt(enc)
class AppleDeveloperUid(AesBaseCrypt):
...
class WeixinLoginUid(AesBaseCrypt):
...
def make_from_user_uuid(uid):
random_str = uuid.uuid1().__str__().split("-")[0:-1]
user_ran_str = uuid.uuid5(uuid.NAMESPACE_DNS, uid).__str__().split("-")

@ -199,8 +199,7 @@ class AuthConfCache(WechatConfCache):
@property
def NOTIFY(self):
# return super().get_value('NOTIFY', AUTHCONF.NOTIFY)
return AUTHCONF.NOTIFY
return super().get_value('NOTIFY', AUTHCONF.NOTIFY)
@property
def LOGIN(self):

@ -56,8 +56,8 @@ def get_wx_access_token_cache(c_count=1, ):
return get_wx_access_token_cache(c_count + 1)
def create_menu():
menu_json = {
def create_menu(menu_json=None):
default_menu_json = {
"button": [
{
"type": "click",
@ -79,14 +79,19 @@ def create_menu():
},
{
"type": "click",
"name": "查询登录绑定",
"name": "查询当前绑定",
"key": "query_bind"
},
{
"type": "click",
"name": "解除登录绑定",
"key": "unbind"
"name": "解除所有绑定",
"key": "unbind_all"
},
{
"type": "click",
"name": "账户解绑管理",
"key": "unbind"
}
]
},
{
@ -96,6 +101,17 @@ def create_menu():
}
]
}
if menu_json is None:
menu_json = default_menu_json
try:
if isinstance(menu_json, str):
menu_json = json.loads(menu_json)
if not isinstance(menu_json, dict):
logger.error(f"menu json check failed menu_json:{menu_json}")
return
except Exception as e:
logger.error(f"menu json check failed menu_json:{menu_json} Exception:{e}")
return
p_url = f"https://api.weixin.qq.com/cgi-bin/menu/create?access_token={get_wx_access_token_cache()}"
req = requests.post(url=p_url, data=json.dumps(menu_json, ensure_ascii=False).encode('utf-8'))
print(req.json())
@ -202,8 +218,6 @@ class WxTemplateMsg(object):
登录系统OA系统
登录时间2014-11-28 10:06:32
如有疑问请致电IT服务台400-888-8888 关注公众号在线反馈
:param to_user:
:param wx_nick_name: 微信昵称
:param username: flyapps 用户昵称
:return:
"""
@ -302,7 +316,7 @@ class WxTemplateMsg(object):
}
return self.send_msg(msg_id, content_data)
def unbind_success_msg(self, username):
def unbind_success_msg(self, username, context, description):
now_time = get_format_time()
msg_id = 'RabYMg8-jPGhonk957asbW17iLHSLp8BfEXnyesRZ60'
content_data = {
@ -319,11 +333,11 @@ class WxTemplateMsg(object):
"color": "#173177"
},
"keyword3": {
"value": "解除绑定成功,您将无法使用微信扫描登录平台",
"value": context,
"color": "#173177"
},
"remark": {
"value": "如需重新绑定,请登陆平台,在个人资料进行绑定。感谢您的关注",
"value": description,
"color": "#173177"
},
}

@ -68,7 +68,7 @@ def sign_unavailable_developer(user_obj, app_obj):
"""
message_type = 3
now_time = get_format_time().replace('_', ' ')
msg = Config.MSG_NOT_EXIST_DEVELOPER % (user_obj.first_name, now_time, app_obj.name)
msg = Config.MSG_NOT_EXIST_DEVELOPER % (user_obj.first_name, app_obj.name, now_time)
for wx_user_obj in get_notify_wx_queryset(user_obj, message_type):
res = WxTemplateMsg(wx_user_obj.openid, wx_user_obj.nickname).operate_failed_msg(
user_obj.first_name, f'应用 {app_obj.name} 签名失败了',

@ -292,7 +292,7 @@ FILE_UPLOAD_TMP_KEY = ".tmp"
SYNC_CACHE_TO_DATABASE = {
'download_times': 10, # 下载次数同步时间
'best_proxy_ips_times': 60 * 60, # 代理ip 自动获取时间
'best_proxy_ips_times': 6 * 60 * 60, # 代理ip 自动获取时间
'wx_get_access_token_times': 60 * 10, # 微信access_token 自动获取时间
'try_login_times': (10, 12 * 60 * 60), # 当天登录失败次数,超过该失败次数,锁定24小时
'auto_clean_tmp_file_times': 60 * 30, # 定时清理上传失误生成的临时文件
@ -471,13 +471,13 @@ CELERY_BEAT_SCHEDULE = {
'download_times_notify_check_job': {
'task': 'api.tasks.download_times_notify_check_job',
# 'schedule': SYNC_CACHE_TO_DATABASE.get("auto_check_ios_developer_active_times"),
'schedule': crontab(hour=1, minute=10),
'schedule': crontab(hour='6,12,18', minute=10),
'args': ()
},
'apple_developer_devices_check_job': {
'task': 'api.tasks.apple_developer_devices_check_job',
# 'schedule': SYNC_CACHE_TO_DATABASE.get("auto_check_ios_developer_active_times"),
'schedule': crontab(hour=1, minute=20),
'schedule': crontab(hour='6,12,18', minute=20),
'args': ()
},
'apple_developer_cert_notify_check_job': {
@ -491,11 +491,11 @@ CELERY_BEAT_SCHEDULE = {
'schedule': SYNC_CACHE_TO_DATABASE.get("wx_get_access_token_times"),
'args': (),
},
'get_best_proxy_ips_job': {
'task': 'xsign.tasks.get_best_proxy_ips_job',
'schedule': SYNC_CACHE_TO_DATABASE.get("best_proxy_ips_times"),
'args': (),
},
# 'get_best_proxy_ips_job': {
# 'task': 'xsign.tasks.get_best_proxy_ips_job',
# 'schedule': SYNC_CACHE_TO_DATABASE.get("best_proxy_ips_times"),
# 'args': (),
# },
'auto_check_ios_developer_active_job': {
'task': 'xsign.tasks.auto_check_ios_developer_active_job',
# 'schedule': SYNC_CACHE_TO_DATABASE.get("auto_check_ios_developer_active_times"),

@ -17,8 +17,12 @@ logger = logging.getLogger(__name__)
def get_best_proxy_ips(url='https://api.appstoreconnect.apple.com/agreement'):
active_proxy_ips = [proxy_info['proxy'] for proxy_info in Config.APPLE_DEVELOPER_API_PROXY_LIST if
proxy_info.get('active')]
try:
active_proxy_ips = [proxy_info['proxy'] for proxy_info in Config.APPLE_DEVELOPER_API_PROXY_LIST if
proxy_info.get('active')]
except Exception as e:
logger.error(f'get_best_proxy_ips failed Exception:{e}')
return
access_ip_info = []
if not active_proxy_ips:
return
@ -39,7 +43,7 @@ def get_best_proxy_ips(url='https://api.appstoreconnect.apple.com/agreement'):
pools.shutdown()
best_sorted_ips = sorted(access_ip_info, key=lambda x: x.get('time'))[:8]
best_sorted_ips = [ip_proxy['ip'] for ip_proxy in best_sorted_ips]
IpProxyListCache().set_storage_cache(best_sorted_ips, 24 * 60 * 60)
IpProxyListCache().set_storage_cache(best_sorted_ips, 6 * 60 * 60)
return best_sorted_ips
@ -73,7 +77,7 @@ def get_proxy_ip_from_cache(change_ip=False):
else:
proxy_info = Config.APPLE_DEVELOPER_API_PROXY
logger.info(f"make ip proxy cache {proxy_info}")
active_proxy_cache.set_storage_cache(proxy_info, 24 * 60 * 60)
active_proxy_cache.set_storage_cache(proxy_info, 60 * 60)
return proxy_info

@ -617,7 +617,7 @@ class IosUtils(object):
return status, device_obj
if device_obj and device_obj.status not in ['ENABLED', 'DISABLED']:
if not IosUtils.check_device_status(developer_obj)[0]:
if not IosUtils.check_device_status(developer_obj, org_device_obj=device_obj)[0]:
return False, 'UNEXPECTED_ERROR'
sync_device_obj, _ = update_or_create_developer_udid_info(device_obj, developer_obj)
@ -683,7 +683,7 @@ class IosUtils(object):
@staticmethod
@call_function_try_attempts(try_attempts=2)
def check_device_status(developer_obj, device_obj_list=None):
def check_device_status(developer_obj, device_obj_list=None, org_device_obj=None):
status = True
if device_obj_list is None:
status, device_obj_list = get_api_obj(developer_obj).get_device()
@ -693,6 +693,9 @@ class IosUtils(object):
developer_obj.status = 5
developer_obj.save(update_fields=['status'])
return False, f'issuer_id:{developer_obj.issuer_id} device status unexpected. device_obj:{device_obj}'
else:
if org_device_obj and org_device_obj.id == device_obj.id:
org_device_obj.status = True if device_obj.status == 'ENABLED' else False
return True, ''
@staticmethod
@ -1187,7 +1190,10 @@ class IosUtils(object):
udid_result_list = [device.udid for device in result]
udid_same = set(udid_result_list) & set(udid_developer_list)
same_p = (len(udid_same) / len(udid_result_list) + len(udid_same) / len(udid_developer_list)) / 2
if len(udid_result_list) > 0 and len(udid_developer_list) > 0:
same_p = (len(udid_same) / len(udid_result_list) + len(udid_same) / len(udid_developer_list)) / 2
else:
same_p = 0
# 获取设备列表的时候,有时候会发生灵异事件,尝试多次获取 【也可能是未知bug导致】【已经存在,获取的数据并不是该用户数据】
if status and ((isinstance(result, list) and len(result) == 0) or same_p < 0.8):
time.sleep(2)

@ -265,13 +265,16 @@ class DeveloperView(APIView):
}
try:
logger.error(f"user {request.user} add new developer {data.get('issuer_id', '')} data {data_info}")
developer_obj = AppIOSDeveloperInfo.objects.create(user_id=request.user, **data_info)
developer_obj, created = AppIOSDeveloperInfo.objects.update_or_create(user_id=request.user,
issuer_id=data_info.get('issuer_id'),
defaults=data_info)
IosUtils.create_developer_space(developer_obj, request.user)
status, result = IosUtils.active_developer(developer_obj, False)
if not status:
res.code = 1008
res.msg = result.get("return_info", "未知错误")
delete_developer_and_clean(developer_obj, request.user)
if created:
delete_developer_and_clean(developer_obj, request.user)
return Response(res.dict)
else:
IosUtils.get_device_from_developer(developer_obj)
@ -279,7 +282,7 @@ class DeveloperView(APIView):
except Exception as e:
logger.error(f"user {request.user} create developer {data_info} failed Exception:{e}")
res.code = 1005
res.msg = "添加失败"
res.msg = f"添加失败 {e}"
return Response(res.dict)
return self.get(request)

Loading…
Cancel
Save