import base64 import json from datetime import datetime from django.utils.module_loading import import_string from rest_framework import serializers from apps.jqr.models import JqrHookUser from apps.jqr.pubsub import JQREventCallbackPubSub from apps.jqr.tasks import save_add_contact, delete_add_contact, edit_add_contact, save_add_contact_by_channel, \ edit_add_contact_by_channel, delete_add_contact_by_channel from apps.msg.models import TbMessage from apps.msg.pubsub import JQRMSGPubSub from apps.qc.choices import QcCorpInfoCallbackStatusChoices from libs.weworkapi.callback.WXBizMsgCrypt3 import WXBizMsgCrypt, Prpcrypt from utils.tools import sha1_encoder, get_attribute, camel_to_snake from utils.base_serializer import BaseSerializer, CurrentIpDefault import xml.etree.cElementTree as ET class WechatPublicTokenSerializer(serializers.Serializer): msg_signature = serializers.CharField() echostr = serializers.CharField() timestamp = serializers.CharField() nonce = serializers.CharField() def validate(self, attrs): corp = self.context.get('corp') token = corp.token corpid = corp.corpid encoding_aes_key = corp.encodingaeskey msg_signature = attrs.get('msg_signature') echostr = attrs.get('echostr') timestamp = attrs.get('timestamp') nonce = attrs.get('nonce') # # 1)将token、timestamp、nonce, echostr四个参数进行字典序排序 # arr = [token, timestamp, nonce, echostr] # arr.sort() # # 2)将三个参数字符串拼接成一个字符串进行sha1加密 # data = "".join(arr) # # 3)开发者获得加密后的字符串可与 signature 对比,标识该请求来源于微信 # encode_str = sha1_encoder(data) wxcpt = WXBizMsgCrypt(token, encoding_aes_key, corpid) ret, echostr = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr) if ret != 0: return {} corp.callbackstatus = QcCorpInfoCallbackStatusChoices.VALIDATED corp.callback_validate_time = datetime.now() attrs['echostr'] = echostr.decode() return attrs class WechatEncryptSerializer(serializers.Serializer): ToUserName = serializers.CharField(write_only=True) Encrypt = serializers.CharField(write_only=True) AgentID = serializers.CharField(write_only=True) def create(self, data): corp = self.context.get('corp') encoding_aes_key = corp.encodingaeskey encrypt = data.get('Encrypt') xmltext = self.decrypt(encrypt, encoding_aes_key) data = self.parse_xml(xmltext) print(data) event = data.get('event') changetype = data.get('changetype') event_handler = getattr(self, f'handle_{event}_{changetype}', None) print(f'handle_{event}_{changetype}') if event_handler: event_handler(data) return {} def decrypt(self, encrypt, encoding_key): try: key = base64.b64decode(encoding_key + "=") prpcrypt = Prpcrypt(key) corpid = '' res, decrypt = prpcrypt.decrypt(encrypt, corpid) if res != 0: return decrypt = decrypt.decode() return decrypt except Exception as e: print(e) def parse_xml(self, xmltext): xml_tree = ET.fromstring(xmltext) data = {} for child in xml_tree: tag = child.tag key = camel_to_snake(tag) key = ''.join(key.split('_')) data[key] = get_attribute(xml_tree.find(tag), 'text') return data def handle_change_external_contact_add_external_contact(self, data): """ 处理添加企业客户事件 """ print('添加客户事件') corp = self.context.get('corp') data.pop('tousername') print(data) state = data.get('state') data['corpid'] = corp.corpid if state and state.startswith('mg') and '_' in state: [_, _, qrcodeid] = state.split('_') data['qrcodeid'] = qrcodeid data['agentid'] = corp.agentid data['uid'] = corp.uid # save_add_contact.delay(data, corp.to_dict(['corpid', 'appsecret'])) JQREventCallbackPubSub.publish({ 'handler': f'{save_add_contact_by_channel.__module__}.{save_add_contact_by_channel.__name__}', 'data': json.dumps(data), 'corpinfo': corp.to_dict(['corpid', 'appsecret']), }) def handle_change_external_contact_edit_external_contact(self, data): """ 处理编辑企业客户事件 """ print('编辑客户事件') corp = self.context.get('corp') data.pop('tousername') print(data) state = data.get('state') data['corpid'] = corp.corpid if state and state.startswith('mg') and '_' in state: [_, _, qrcodeid] = state.split('_') data['qrcodeid'] = qrcodeid data['agentid'] = corp.agentid data['uid'] = corp.uid # edit_add_contact.delay(data, corp.to_dict(['corpid', 'appsecret'])) JQREventCallbackPubSub.publish({ 'handler': f'{edit_add_contact_by_channel.__module__}.{save_add_contact_by_channel.__name__}', 'data': json.dumps(data), 'corpinfo': corp.to_dict(['corpid', 'appsecret']), }) def handle_change_external_contact_add_half_external_contact(self, data): """ 处理外部联系人免验证添加成员事件 """ print('外部联系人免验证添加成员事件') corp = self.context.get('corp') data.pop('tousername') print(data) state = data.get('state') data['corpid'] = corp.corpid if state and state.startswith('mg') and '_' in state: [_, _, qrcodeid] = state.split('_') data['qrcodeid'] = qrcodeid data['agentid'] = corp.agentid data['uid'] = corp.uid # save_add_contact.delay(data, corp.to_dict(['corpid', 'appsecret'])) JQREventCallbackPubSub.publish({ 'handler': f'{save_add_contact_by_channel.__module__}.{save_add_contact_by_channel.__name__}', 'data': json.dumps(data), 'corpinfo': corp.to_dict(['corpid', 'appsecret']), }) def handle_change_external_contact_del_follow_user(self, data): """ 处理删除跟进成员事件 (客户删我们) """ print('删除跟进成员事件') corp = self.context.get('corp') data.pop('tousername') print(data) state = data.get('state') data['corpid'] = corp.corpid if state and state.startswith('mg') and '_' in state: data['agentid'] = corp.agentid data['uid'] = corp.uid # delete_add_contact.delay(data, corp.to_dict(['corpid', 'appsecret'])) JQREventCallbackPubSub.publish({ 'handler': f'{delete_add_contact_by_channel.__module__}.{delete_add_contact.__name__}', 'data': json.dumps(data), 'corpinfo': corp.to_dict(['corpid', 'appsecret']), }) def handle_change_external_chat_create(self, data): """ 处理客户群创建事件 """ print('客户群创建事件') print(data) def handle_change_external_chat_update(self, data): """ 处理客户群更新事件 """ print('客户群更新事件') print(data) def handle_change_external_chat_dismiss(self, data): """ 处理客户群解散事件 """ print('客户群解散事件') print(data) class HeartBeatSerializer(BaseSerializer): ip = serializers.HiddenField(default=CurrentIpDefault()) class Meta: validators = [] model = JqrHookUser fields = '__all__' def create(self, validated_data): corpid = validated_data.get('corpid') userid = validated_data.get('userid') obj, _ = JqrHookUser.objects.update_or_create( defaults=validated_data, corpid=corpid, userid=userid, ) return obj class TbMessageModelSerializer(BaseSerializer): class Meta: model = TbMessage fields = '__all__' def create(self, validated_data): JQRMSGPubSub.publish({ **self.context.get('request').data, 'corpid': validated_data.get('corpid'), 'userid': validated_data.get('userid'), }) return TbMessage(**validated_data)