diff --git a/fir_client/src/components/FirLogin.vue b/fir_client/src/components/FirLogin.vue
index 6a01a57..286fba5 100644
--- a/fir_client/src/components/FirLogin.vue
+++ b/fir_client/src/components/FirLogin.vue
@@ -74,7 +74,29 @@
-
或使用以下账户登录
+
+
+
+
+
+
+
+
+
+ {{ userinfo.first_name }}
+
+
+
+
+
+
+ 或使用以下账户登录
+
{
+ 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",
diff --git a/fir_client/vue.config.js b/fir_client/vue.config.js
index 1f44f6d..dcc2780 100644
--- a/fir_client/vue.config.js
+++ b/fir_client/vue.config.js
@@ -82,7 +82,7 @@ if (page) {
}
}
-const version='2.2.5';
+const version='2.2.6';
const pro_base_env = {
baseUrl: 'https://flyapps.cn',
diff --git a/fir_ser/api/management/commands/create_weixin_menu.py b/fir_ser/api/management/commands/create_weixin_menu.py
new file mode 100644
index 0000000..7cdb8a8
--- /dev/null
+++ b/fir_ser/api/management/commands/create_weixin_menu.py
@@ -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))
diff --git a/fir_ser/api/migrations/0005_auto_20220329_1131.py b/fir_ser/api/migrations/0005_auto_20220329_1131.py
new file mode 100644
index 0000000..f4e9b38
--- /dev/null
+++ b/fir_ser/api/migrations/0005_auto_20220329_1131.py
@@ -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')},
+ ),
+ ]
diff --git a/fir_ser/api/models.py b/fir_ser/api/models.py
index 5cc63c3..4520f91 100644
--- a/fir_ser/api/models.py
+++ b/fir_ser/api/models.py
@@ -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}"
diff --git a/fir_ser/api/urls.py b/fir_ser/api/urls.py
index 62d9e73..409a9ce 100644
--- a/fir_ser/api/urls.py
+++ b/fir_ser/api/urls.py
@@ -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()),
diff --git a/fir_ser/api/utils/serializer.py b/fir_ser/api/utils/serializer.py
index 9e70ec4..787ebe2 100644
--- a/fir_ser/api/utils/serializer.py
+++ b/fir_ser/api/utils/serializer.py
@@ -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
diff --git a/fir_ser/api/views/getip.py b/fir_ser/api/views/getip.py
new file mode 100644
index 0000000..922d808
--- /dev/null
+++ b/fir_ser/api/views/getip.py
@@ -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)})
diff --git a/fir_ser/api/views/login_wx.py b/fir_ser/api/views/login_wx.py
index 61b97e7..2a601d3 100644
--- a/fir_ser/api/views/login_wx.py
+++ b/fir_ser/api/views/login_wx.py
@@ -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()
diff --git a/fir_ser/api/views/thirdlogin.py b/fir_ser/api/views/thirdlogin.py
index c2a4adb..74de50d 100644
--- a/fir_ser/api/views/thirdlogin.py
+++ b/fir_ser/api/views/thirdlogin.py
@@ -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'【解除登录绑定】'
+ if wx_user_obj.enable_notify:
+ notify_info = f'解除消息绑定 {user_obj.uid}'
+ content += f'【解除消息绑定】'
+ 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")
diff --git a/fir_ser/common/base/baseutils.py b/fir_ser/common/base/baseutils.py
index 654f4d7..3116f6c 100644
--- a/fir_ser/common/base/baseutils.py
+++ b/fir_ser/common/base/baseutils.py
@@ -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("-")
diff --git a/fir_ser/common/core/sysconfig.py b/fir_ser/common/core/sysconfig.py
index 29642d4..dd666dc 100644
--- a/fir_ser/common/core/sysconfig.py
+++ b/fir_ser/common/core/sysconfig.py
@@ -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):
diff --git a/fir_ser/common/libs/mp/wechat.py b/fir_ser/common/libs/mp/wechat.py
index 53294e4..73ddc8d 100644
--- a/fir_ser/common/libs/mp/wechat.py
+++ b/fir_ser/common/libs/mp/wechat.py
@@ -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"
},
}
diff --git a/fir_ser/common/notify/notify.py b/fir_ser/common/notify/notify.py
index 3135eec..2463180 100644
--- a/fir_ser/common/notify/notify.py
+++ b/fir_ser/common/notify/notify.py
@@ -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} 签名失败了',
diff --git a/fir_ser/fir_ser/settings.py b/fir_ser/fir_ser/settings.py
index 54efffb..b267694 100644
--- a/fir_ser/fir_ser/settings.py
+++ b/fir_ser/fir_ser/settings.py
@@ -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"),
diff --git a/fir_ser/xsign/utils/iproxy.py b/fir_ser/xsign/utils/iproxy.py
index 1d73d9f..0521841 100644
--- a/fir_ser/xsign/utils/iproxy.py
+++ b/fir_ser/xsign/utils/iproxy.py
@@ -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
diff --git a/fir_ser/xsign/utils/supersignutils.py b/fir_ser/xsign/utils/supersignutils.py
index 3b292b1..b84160f 100644
--- a/fir_ser/xsign/utils/supersignutils.py
+++ b/fir_ser/xsign/utils/supersignutils.py
@@ -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)
diff --git a/fir_ser/xsign/views/supersign.py b/fir_ser/xsign/views/supersign.py
index 0697533..1055dac 100644
--- a/fir_ser/xsign/views/supersign.py
+++ b/fir_ser/xsign/views/supersign.py
@@ -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)