2023-12-13 16:09:16 +08:00
|
|
|
|
import base64
|
2023-12-25 11:06:08 +08:00
|
|
|
|
import json
|
2023-12-22 10:28:32 +08:00
|
|
|
|
from datetime import datetime
|
2023-12-13 16:09:16 +08:00
|
|
|
|
|
|
|
|
|
from rest_framework import serializers
|
|
|
|
|
|
2023-12-20 17:50:07 +08:00
|
|
|
|
from apps.jqr.models import JqrHookUser
|
2023-12-26 10:05:06 +08:00
|
|
|
|
from apps.jqr.pubsub import JQREventNewUserCallbackPubSub, JQREventCallbackPubSub
|
2023-12-25 11:06:08 +08:00
|
|
|
|
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
|
2023-12-21 14:46:34 +08:00
|
|
|
|
from apps.msg.models import TbMessage
|
2023-12-25 11:34:35 +08:00
|
|
|
|
from apps.msg.pubsub import JQRMSGPubSub
|
2023-12-22 10:28:32 +08:00
|
|
|
|
from apps.qc.choices import QcCorpInfoCallbackStatusChoices
|
2023-12-13 16:09:16 +08:00
|
|
|
|
from libs.weworkapi.callback.WXBizMsgCrypt3 import WXBizMsgCrypt, Prpcrypt
|
2023-12-14 15:29:55 +08:00
|
|
|
|
from utils.tools import sha1_encoder, get_attribute, camel_to_snake
|
2023-12-13 16:09:16 +08:00
|
|
|
|
import xml.etree.cElementTree as ET
|
2023-12-26 17:00:52 +08:00
|
|
|
|
from utils.base_serializer import BaseSerializer, CurrentIpDefault
|
2023-12-13 16:09:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class WechatPublicTokenSerializer(serializers.Serializer):
|
|
|
|
|
msg_signature = serializers.CharField()
|
|
|
|
|
echostr = serializers.CharField()
|
|
|
|
|
timestamp = serializers.CharField()
|
|
|
|
|
nonce = serializers.CharField()
|
|
|
|
|
|
|
|
|
|
def validate(self, attrs):
|
2023-12-14 13:22:07 +08:00
|
|
|
|
corp = self.context.get('corp')
|
|
|
|
|
token = corp.token
|
|
|
|
|
corpid = corp.corpid
|
|
|
|
|
encoding_aes_key = corp.encodingaeskey
|
2023-12-13 16:09:16 +08:00
|
|
|
|
msg_signature = attrs.get('msg_signature')
|
|
|
|
|
echostr = attrs.get('echostr')
|
|
|
|
|
timestamp = attrs.get('timestamp')
|
|
|
|
|
nonce = attrs.get('nonce')
|
2023-12-14 13:22:07 +08:00
|
|
|
|
# # 1)将token、timestamp、nonce, echostr四个参数进行字典序排序
|
|
|
|
|
# arr = [token, timestamp, nonce, echostr]
|
|
|
|
|
# arr.sort()
|
|
|
|
|
# # 2)将三个参数字符串拼接成一个字符串进行sha1加密
|
|
|
|
|
# data = "".join(arr)
|
|
|
|
|
# # 3)开发者获得加密后的字符串可与 signature 对比,标识该请求来源于微信
|
|
|
|
|
# encode_str = sha1_encoder(data)
|
2023-12-13 16:09:16 +08:00
|
|
|
|
wxcpt = WXBizMsgCrypt(token, encoding_aes_key, corpid)
|
|
|
|
|
ret, echostr = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr)
|
|
|
|
|
if ret != 0:
|
|
|
|
|
return {}
|
2023-12-22 10:28:32 +08:00
|
|
|
|
corp.callbackstatus = QcCorpInfoCallbackStatusChoices.VALIDATED
|
|
|
|
|
corp.callback_validate_time = datetime.now()
|
2023-12-28 13:39:25 +08:00
|
|
|
|
corp.save()
|
2023-12-13 16:09:16 +08:00
|
|
|
|
attrs['echostr'] = echostr.decode()
|
2023-12-14 13:22:07 +08:00
|
|
|
|
return attrs
|
2023-12-13 16:09:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class WechatEncryptSerializer(serializers.Serializer):
|
2023-12-14 15:29:55 +08:00
|
|
|
|
ToUserName = serializers.CharField(write_only=True)
|
|
|
|
|
Encrypt = serializers.CharField(write_only=True)
|
|
|
|
|
AgentID = serializers.CharField(write_only=True)
|
2023-12-13 16:09:16 +08:00
|
|
|
|
|
2023-12-14 15:29:55 +08:00
|
|
|
|
def create(self, data):
|
2023-12-14 14:42:38 +08:00
|
|
|
|
corp = self.context.get('corp')
|
|
|
|
|
encoding_aes_key = corp.encodingaeskey
|
2023-12-14 15:29:55 +08:00
|
|
|
|
encrypt = data.get('Encrypt')
|
2023-12-13 16:09:16 +08:00
|
|
|
|
xmltext = self.decrypt(encrypt, encoding_aes_key)
|
|
|
|
|
data = self.parse_xml(xmltext)
|
|
|
|
|
print(data)
|
2023-12-14 15:42:21 +08:00
|
|
|
|
event = data.get('event')
|
2023-12-14 18:43:01 +08:00
|
|
|
|
changetype = data.get('changetype')
|
|
|
|
|
event_handler = getattr(self, f'handle_{event}_{changetype}', None)
|
|
|
|
|
print(f'handle_{event}_{changetype}')
|
2023-12-14 15:42:21 +08:00
|
|
|
|
if event_handler:
|
|
|
|
|
event_handler(data)
|
2023-12-14 15:29:55 +08:00
|
|
|
|
return {}
|
2023-12-13 16:09:16 +08:00
|
|
|
|
|
|
|
|
|
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)
|
2023-12-14 15:29:55 +08:00
|
|
|
|
data = {}
|
|
|
|
|
for child in xml_tree:
|
|
|
|
|
tag = child.tag
|
|
|
|
|
key = camel_to_snake(tag)
|
2023-12-14 18:43:01 +08:00
|
|
|
|
key = ''.join(key.split('_'))
|
|
|
|
|
data[key] = get_attribute(xml_tree.find(tag), 'text')
|
2023-12-14 15:29:55 +08:00
|
|
|
|
return data
|
2023-12-14 15:42:21 +08:00
|
|
|
|
|
|
|
|
|
def handle_change_external_contact_add_external_contact(self, data):
|
|
|
|
|
"""
|
|
|
|
|
处理添加企业客户事件
|
|
|
|
|
"""
|
2023-12-14 18:43:01 +08:00
|
|
|
|
print('添加客户事件')
|
|
|
|
|
corp = self.context.get('corp')
|
|
|
|
|
data.pop('tousername')
|
2023-12-14 15:42:21 +08:00
|
|
|
|
print(data)
|
2023-12-21 17:17:07 +08:00
|
|
|
|
state = data.get('state')
|
2023-12-21 17:20:53 +08:00
|
|
|
|
data['corpid'] = corp.corpid
|
2023-12-21 17:17:07 +08:00
|
|
|
|
if state and state.startswith('mg') and '_' in state:
|
2024-01-04 14:04:24 +08:00
|
|
|
|
[_, uid, qrcodeid] = state.split('_')
|
2023-12-25 11:06:08 +08:00
|
|
|
|
data['qrcodeid'] = qrcodeid
|
2023-12-21 17:17:07 +08:00
|
|
|
|
data['agentid'] = corp.agentid
|
2024-01-04 14:04:24 +08:00
|
|
|
|
data['uid'] = uid
|
2023-12-25 11:06:08 +08:00
|
|
|
|
# save_add_contact.delay(data, corp.to_dict(['corpid', 'appsecret']))
|
2023-12-26 10:05:06 +08:00
|
|
|
|
JQREventNewUserCallbackPubSub.publish({
|
2023-12-25 11:06:08 +08:00
|
|
|
|
'handler': f'{save_add_contact_by_channel.__module__}.{save_add_contact_by_channel.__name__}',
|
|
|
|
|
'data': json.dumps(data),
|
|
|
|
|
'corpinfo': corp.to_dict(['corpid', 'appsecret']),
|
|
|
|
|
})
|
2023-12-14 15:42:21 +08:00
|
|
|
|
|
|
|
|
|
def handle_change_external_contact_edit_external_contact(self, data):
|
|
|
|
|
"""
|
|
|
|
|
处理编辑企业客户事件
|
|
|
|
|
"""
|
2023-12-14 18:43:01 +08:00
|
|
|
|
print('编辑客户事件')
|
|
|
|
|
corp = self.context.get('corp')
|
|
|
|
|
data.pop('tousername')
|
|
|
|
|
print(data)
|
2023-12-21 17:17:07 +08:00
|
|
|
|
state = data.get('state')
|
2023-12-21 17:20:53 +08:00
|
|
|
|
data['corpid'] = corp.corpid
|
2023-12-21 17:17:07 +08:00
|
|
|
|
if state and state.startswith('mg') and '_' in state:
|
2024-01-04 14:04:24 +08:00
|
|
|
|
[_, uid, qrcodeid] = state.split('_')
|
2023-12-25 11:06:08 +08:00
|
|
|
|
data['qrcodeid'] = qrcodeid
|
2023-12-21 17:17:07 +08:00
|
|
|
|
data['agentid'] = corp.agentid
|
2024-01-04 14:04:24 +08:00
|
|
|
|
data['uid'] = uid
|
2023-12-25 11:06:08 +08:00
|
|
|
|
# edit_add_contact.delay(data, corp.to_dict(['corpid', 'appsecret']))
|
|
|
|
|
JQREventCallbackPubSub.publish({
|
2023-12-27 17:30:48 +08:00
|
|
|
|
'handler': f'{edit_add_contact_by_channel.__module__}.{edit_add_contact_by_channel.__name__}',
|
2023-12-25 11:06:08 +08:00
|
|
|
|
'data': json.dumps(data),
|
|
|
|
|
'corpinfo': corp.to_dict(['corpid', 'appsecret']),
|
|
|
|
|
})
|
2023-12-14 18:43:01 +08:00
|
|
|
|
|
|
|
|
|
def handle_change_external_contact_add_half_external_contact(self, data):
|
|
|
|
|
"""
|
|
|
|
|
处理外部联系人免验证添加成员事件
|
|
|
|
|
"""
|
|
|
|
|
print('外部联系人免验证添加成员事件')
|
|
|
|
|
corp = self.context.get('corp')
|
|
|
|
|
data.pop('tousername')
|
|
|
|
|
print(data)
|
2023-12-21 17:17:07 +08:00
|
|
|
|
state = data.get('state')
|
2023-12-21 17:20:53 +08:00
|
|
|
|
data['corpid'] = corp.corpid
|
2023-12-21 17:17:07 +08:00
|
|
|
|
if state and state.startswith('mg') and '_' in state:
|
2024-01-04 14:04:24 +08:00
|
|
|
|
[_, uid, qrcodeid] = state.split('_')
|
2023-12-25 11:06:08 +08:00
|
|
|
|
data['qrcodeid'] = qrcodeid
|
2023-12-21 17:17:07 +08:00
|
|
|
|
data['agentid'] = corp.agentid
|
2024-01-04 14:04:24 +08:00
|
|
|
|
data['uid'] = uid
|
2023-12-25 11:06:08 +08:00
|
|
|
|
# save_add_contact.delay(data, corp.to_dict(['corpid', 'appsecret']))
|
2023-12-26 10:05:06 +08:00
|
|
|
|
JQREventNewUserCallbackPubSub.publish({
|
2023-12-25 11:06:08 +08:00
|
|
|
|
'handler': f'{save_add_contact_by_channel.__module__}.{save_add_contact_by_channel.__name__}',
|
|
|
|
|
'data': json.dumps(data),
|
|
|
|
|
'corpinfo': corp.to_dict(['corpid', 'appsecret']),
|
|
|
|
|
})
|
2023-12-14 18:43:01 +08:00
|
|
|
|
|
|
|
|
|
def handle_change_external_contact_del_follow_user(self, data):
|
|
|
|
|
"""
|
|
|
|
|
处理删除跟进成员事件 (客户删我们)
|
|
|
|
|
"""
|
|
|
|
|
print('删除跟进成员事件')
|
|
|
|
|
corp = self.context.get('corp')
|
|
|
|
|
data.pop('tousername')
|
|
|
|
|
print(data)
|
2023-12-21 17:17:07 +08:00
|
|
|
|
state = data.get('state')
|
2023-12-21 17:20:53 +08:00
|
|
|
|
data['corpid'] = corp.corpid
|
2023-12-21 17:17:07 +08:00
|
|
|
|
if state and state.startswith('mg') and '_' in state:
|
2024-01-04 14:04:24 +08:00
|
|
|
|
[_, uid, qrcodeid] = state.split('_')
|
2023-12-21 17:17:07 +08:00
|
|
|
|
data['agentid'] = corp.agentid
|
2024-01-04 14:04:24 +08:00
|
|
|
|
data['uid'] = uid
|
2023-12-25 11:06:08 +08:00
|
|
|
|
# delete_add_contact.delay(data, corp.to_dict(['corpid', 'appsecret']))
|
|
|
|
|
JQREventCallbackPubSub.publish({
|
2023-12-26 16:54:35 +08:00
|
|
|
|
'handler': f'{delete_add_contact_by_channel.__module__}.{delete_add_contact_by_channel.__name__}',
|
2023-12-25 11:06:08 +08:00
|
|
|
|
'data': json.dumps(data),
|
|
|
|
|
'corpinfo': corp.to_dict(['corpid', 'appsecret']),
|
|
|
|
|
})
|
2023-12-14 18:43:01 +08:00
|
|
|
|
|
|
|
|
|
def handle_change_external_chat_create(self, data):
|
|
|
|
|
"""
|
|
|
|
|
处理客户群创建事件
|
|
|
|
|
"""
|
|
|
|
|
print('客户群创建事件')
|
|
|
|
|
print(data)
|
2023-12-26 10:05:06 +08:00
|
|
|
|
corp = self.context.get('corp')
|
|
|
|
|
data['chat_id'] = data.pop('chatid')
|
2023-12-14 18:43:01 +08:00
|
|
|
|
|
|
|
|
|
def handle_change_external_chat_update(self, data):
|
|
|
|
|
"""
|
|
|
|
|
处理客户群更新事件
|
|
|
|
|
"""
|
|
|
|
|
print('客户群更新事件')
|
|
|
|
|
print(data)
|
|
|
|
|
|
|
|
|
|
def handle_change_external_chat_dismiss(self, data):
|
|
|
|
|
"""
|
|
|
|
|
处理客户群解散事件
|
|
|
|
|
"""
|
|
|
|
|
print('客户群解散事件')
|
|
|
|
|
print(data)
|
2023-12-20 17:50:07 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class HeartBeatSerializer(BaseSerializer):
|
2023-12-21 14:46:34 +08:00
|
|
|
|
ip = serializers.HiddenField(default=CurrentIpDefault())
|
2023-12-20 17:50:07 +08:00
|
|
|
|
|
|
|
|
|
class Meta:
|
2023-12-21 14:46:34 +08:00
|
|
|
|
validators = []
|
2023-12-20 17:50:07 +08:00
|
|
|
|
model = JqrHookUser
|
|
|
|
|
fields = '__all__'
|
2023-12-21 14:46:34 +08:00
|
|
|
|
|
|
|
|
|
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__'
|
|
|
|
|
|
2023-12-21 17:17:07 +08:00
|
|
|
|
def create(self, validated_data):
|
2023-12-25 11:34:35 +08:00
|
|
|
|
JQRMSGPubSub.publish({
|
2023-12-22 16:02:21 +08:00
|
|
|
|
**self.context.get('request').data,
|
|
|
|
|
'corpid': validated_data.get('corpid'),
|
|
|
|
|
'userid': validated_data.get('userid'),
|
|
|
|
|
})
|
2023-12-21 17:17:07 +08:00
|
|
|
|
return TbMessage(**validated_data)
|
2023-12-21 14:46:34 +08:00
|
|
|
|
|