dingxin_toolbox
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
11 KiB

import datetime
import json
import re
import time
import requests
import xml.etree.ElementTree
from urllib.parse import urljoin
from django.db.models import Q
from django_filters.rest_framework import DjangoFilterBackend
from django_redis import get_redis_connection
from rest_framework import filters
from rest_framework import viewsets
from django.views.decorators.csrf import csrf_exempt
from django.http.response import JsonResponse, HttpResponse
# from rest_framework.response import Response
from django.utils import timezone
from dspt_api.util.handle_goods import format_goods
from dspt_api.util.random_params import random_params
from dspt_api.util.sign import Sign
from dspt_api.models import EcChannel, EcEnv, EcApi, EcApiParams, EcCinemaIds, EcRequestLog, EcApiGroup
from dspt_api.serializers import EcChannelSerializer, EcEnvSerializer, EcApiSerializer, EcApiParamsSerializer, \
EcCinemaIdsSerializer, EcRequestLogSerializer, EcApiGroupSerializer
from dspt_api.util.suggest_params import suggest_params, suggest_params_timestamp
from dspt_api.util.general.handle_xml_resp import HandleXmlResp
from dspt_api.util.general.format_xml import format_xml
# Create your views here.
class EcChannelViewSet(viewsets.ModelViewSet):
queryset = EcChannel.objects.all()
serializer_class = EcChannelSerializer
class EcEnvViewSet(viewsets.ModelViewSet):
queryset = EcEnv.objects.all()
serializer_class = EcEnvSerializer
class EcApiViewSet(viewsets.ModelViewSet):
queryset = EcApi.objects.order_by('order').all()
serializer_class = EcApiSerializer
filter_backends = (DjangoFilterBackend,)
# http://172.16.1.114:8000/ec/get_api?type=nonmember
filterset_fields = ('type',)
class EcApiParamsViewSet(viewsets.ModelViewSet):
queryset = EcApiParams.objects.all()
serializer_class = EcApiParamsSerializer
filter_backends = (DjangoFilterBackend,)
# http://172.16.1.114:8000/ec/get_api_params?api_id=1
filterset_fields = ('api_id',)
class EcCinemaIdsViewSet(viewsets.ModelViewSet):
queryset = EcCinemaIds.objects.all()
serializer_class = EcCinemaIdsSerializer
class EcRequestLogViewSet(viewsets.ModelViewSet):
queryset = EcRequestLog.objects.all()
serializer_class = EcRequestLogSerializer
class EcApiGroupViewSet(viewsets.ModelViewSet):
queryset = EcApiGroup.objects.all()
serializer_class = EcApiGroupSerializer
filter_backends = (DjangoFilterBackend,)
# http://172.16.1.114:8000/ec/get_api_group?type=nonmember
filterset_fields = ('type',)
# 内部方法,用于生成requests请求对象
def handle_request(_request):
"""
POST请求参数
env dspt或zyds
member_type member或nonmember
api api地址
params 请求参数
"""
req = json.loads(_request.body)
env = req.get('env')
member_type = req.get('member_type')
api = req.get('api')
params = json.loads(req.get('params'))
resp_format = params['format']
try:
base_url = EcEnv.objects.filter(Q(code=env) & Q(type=member_type)).values('host').first()['host']
except Exception as e:
return False, e
pid = params.get('pid')
try:
key = EcChannel.objects.filter(Q(pid=pid) & Q(env=env)).values('channel_key').first()['channel_key']
except Exception as e:
return False, e
sign = Sign(key)
req_params = sign.add_sig(params)
req_obj = prepare_request(base_url, api, req_params)
return req_obj, req_params['_sig']
# 内部方法,用于拼接请求
def prepare_request(_url, _api, _params):
req = requests.PreparedRequest()
req.prepare_method('GET')
req.prepare_url(url=urljoin(_url, _api), params=_params)
req.prepare_headers({'host': _url[7:]})
return req
@csrf_exempt
def get_api_params_by_api_type(request):
"""
对比接口用于获取指定类型的接口参数
http://172.16.1.168:8000/ec/get_params_by_type?type=nonmember
"""
# 通过Api model获取会员或非会员的api id
_type = request.GET.get('type')
api_list = EcApi.objects.filter(type=_type).values('id')
api_id = [api['id'] for api in api_list]
# 通过 api id 查询对应api的参数
api_params = EcApiParams.objects.filter(api_id__in=api_id)
params_data = EcApiParamsSerializer(api_params, many=True).data
# 组织数据结构,根据api id分组
api_params_dict = {}
for params in params_data:
if params['api_id'] in api_params_dict.keys():
api_params_dict[params['api_id']].append(params)
else:
api_params_dict[params['api_id']] = [params]
return JsonResponse(api_params_dict, json_dumps_params={'ensure_ascii': False})
# 通过接口获取推荐参数的入口函数
@csrf_exempt
def get_suggest_params_by_api(request):
# 获取基础数据
member_type = request.GET.get('member_type')
api = request.GET.get('api')
user_ip = request.META.get('REMOTE_ADDR')
params = suggest_params(member_type, api, user_ip)
return JsonResponse(params, safe=False)
@csrf_exempt
def get_suggest_params_timestamp_by_api(request):
# 获取基础数据
member_type = request.GET.get('member_type')
api = request.GET.get('api')
user_ip = request.META.get('REMOTE_ADDR')
_ts = suggest_params_timestamp(member_type, api, user_ip)
print('timestamp', _ts)
return JsonResponse({'timestamp': _ts})
# 外部接口, 用于实时生成url并返回前端
@csrf_exempt
def general_api_url(request):
"""
此接口为POST接口
request 包含
env dspt或zyds
member_type member或nonmember
api api地址
params 请求参数
"""
# req = json.loads(request.body)
# params = json.loads(req.get('params'))
# resp_format = params['format']
req_obj, sig = handle_request(request)
failed_resp_data = {'url': '请检查foramt、pid参数', 'sig': ''}
result = {'url': req_obj.url, 'sig': sig}
if req_obj is False:
return JsonResponse(failed_resp_data)
return JsonResponse(result)
# 对外接口,用于收集用户提交内容后发送请求
@csrf_exempt
def send_request(request):
"""
request 包含
1. 请求链接 request_url
2. 返回数据 response_data
3. 接口 api
4. 环境 env
"""
# 获取返回类型结果
req = json.loads(request.body)
params = json.loads(req.get('params'))
resp_format = params['format']
member_type = req.get('member_type')
# 初始化redis
redis_conn = get_redis_connection()
user_ip = request.META.get('REMOTE_ADDR')
web_req = json.loads(request.body)
api = web_req.get('api')
redis_key_api = f'dspt_api_{user_ip}_{member_type}_{api}'
# 发送请求
req, sig = handle_request(request)
failed_resp_data = {'url': '请检查foramt、pid参数', 'sig': ''}
if req is False:
return JsonResponse(failed_resp_data)
response = requests.Session().send(req)
print('response', response.content)
# 处理xml数据
handled_data = ''
response_data = ''
if resp_format == 'json':
response_data = response.text
handled_data = json.loads(response.text)
if resp_format == 'xml':
response_data = format_xml(re.sub(r'>\n?\s+?<', r'>\n<', response.text))
handled_data = HandleXmlResp(response.text).format_xml()
# 卖品接口特殊处理去掉无用cate一层结构
if api == 'cinema/goods':
handled_data = format_goods(handled_data)
# 记录Redis
if redis_conn.exists(redis_key_api):
redis_conn.delete(redis_key_api)
data = {
'request_url': req.url,
'member_type': member_type,
'format': resp_format,
'timestamp': int(time.time() * 1000),
'params': params,
'response_data': response.text,
'handled_data': handled_data,
}
print(data)
redis_conn.set(redis_key_api, json.dumps(data), 10 * 60 * 60)
# 插入数据
db_data = {
'ip': user_ip,
'env': web_req.get('env'),
'request': req.url,
'response': response.content,
'request_datetime': timezone.now(),
}
print(db_data)
EcRequestLog.objects.create(**db_data)
# 写入随机值
user_data = {
'user_ip': user_ip,
'member_type': member_type,
'api': api,
'format': resp_format,
}
random_params(user_data, handled_data)
return JsonResponse({'format': resp_format, 'data': response_data, 'handled': json.dumps(handled_data)})
# 对外接口,用于收集用户选择的数据,例如场次,卖品等,以便后续接口直接调用
@csrf_exempt
def set_user_select_data(request):
"""
参数 包含
1. api地址
2. 接口类型 会员 非会员
3. 接口数据类型 json xml
4. 用户选择数据
"""
# 获取返回类型结果
req = json.loads(request.body)
api = req.get('api')
member_type = req.get('member_type')
resp_format = 'xml' if req.get('format') == 'html' else req.get('format')
user_data = req.get('user_data')
user_ip = request.META.get('REMOTE_ADDR')
# 初始化redis
redis_conn = get_redis_connection()
redis_key_user_data = f'dspt_api_{user_ip}_{member_type}_{api}_user_data'
print('user_data', user_data)
# 记录用户选择
data = {
'api': api,
'member_type': member_type,
'format': resp_format,
'timestamp': int(time.time() * 1000),
'user_data': [json.loads(user_data)],
}
print('set_user_select_data', data)
if redis_conn.exists(redis_key_user_data):
redis_conn.delete(redis_key_user_data)
if redis_conn.set(redis_key_user_data, json.dumps(data), 10 * 60 * 60):
return JsonResponse({'result': 'success'})
return JsonResponse({'result': 'fail'})
@csrf_exempt
def clear_user_select_data(request):
"""
参数 包含
1. api地址
2. 接口类型 会员 非会员
"""
# 获取返回类型结果
req = json.loads(request.body)
api = req.get('api')
member_type = req.get('member_type')
user_ip = request.META.get('REMOTE_ADDR')
# 初始化redis
redis_conn = get_redis_connection()
redis_key_user_data = f'dspt_api_{user_ip}_{member_type}_{api}_user_data'
if redis_conn.exists(redis_key_user_data):
if redis_conn.delete(redis_key_user_data):
return JsonResponse({'result': 'success'})
return JsonResponse({'result': 'fail'})
# 对外接口,用于给前端提供上次请求的数据,如果没有则返回数据库中的默认值
# 若果有些字段是依赖于其他接口返回值生成的则单独处理此接口, 单独处理逻辑在util目录下
@csrf_exempt
def get_last_request_data(request):
redis_conn = get_redis_connection()
user_ip = request.META.get('REMOTE_ADDR')
api = request.get('api')
match api:
case '':
pass
case _:
pass