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.

387 lines
13 KiB

import json
import re
import time
import requests
import urllib
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 viewsets
from django.views.decorators.csrf import csrf_exempt
from django.http.response import JsonResponse
# from rest_framework.response import Response
from django.utils import timezone
from dspt_api.util.general.handle_goods import format_goods
from dspt_api.util.general.random_params import random_params
from dspt_api.util.general.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 update.models import Cinema
from update.serializers import CinemaSerializer
from dspt_api.models import EcCinemaIds
from dspt_api.serializers import EcCinemaIdsSerializer
from dspt_api.util.general.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
from dspt_api.util.general.get_cinema_quan import GetQuan
# 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'))
print('handle_request--req.get(params)', 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')
env = request.GET.get('env')
cid = request.GET.get('cid')
pid = request.GET.get('pid')
user_ip = request.META.get('REMOTE_ADDR')
sale_type = request.GET.get('options[sale_type]', None)
print('sale_type', sale_type)
if sale_type is None:
params = suggest_params(member_type, api, env, cid, pid, user_ip)
else:
params = suggest_params(member_type, api, env, cid, pid, user_ip, **{'sale_type': sale_type})
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')
env = request.GET.get('env')
cid = request.GET.get('cid')
pid = request.GET.get('pid')
user_ip = request.META.get('REMOTE_ADDR')
_ts = suggest_params_timestamp(member_type, api, env, cid, pid, 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': urllib.parse.unquote(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'))
print('request_params', params)
resp_format = params['format']
member_type = req.get('member_type')
env = req.get('env')
pid = req.get('pid')
cid = req.get('cid')
# 初始化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}_{env}_{member_type}_{pid}_{cid}_{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()
print('type(handled_data)', type(handled_data))
if str(handled_data['res']['status']) == '0':
return JsonResponse({'format': resp_format, 'data': response_data, 'handled': json.dumps(handled_data)})
# 卖品接口特殊处理去掉无用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,
'env': env,
'cid': cid,
'pid': pid,
}
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')
env = req.get('env')
pid = req.get('pid')
cid = req.get('cid')
# 初始化redis
redis_conn = get_redis_connection()
redis_key_user_data = f'dspt_api_{user_ip}_{env}_{member_type}_{pid}_{cid}_{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'})
@csrf_exempt
def get_quan(request):
"""
请求链接 http://172.16.1.168:8000/ec/get_quan?cid=8125&card_num=81256932698071124424
card_num 传参时查询电子券
"""
cid = request.GET.get('cid')
card_num = request.GET.get('card_num', False)
ec_cinema_info = EcCinemaIds.objects.filter(cid=cid).first()
ec_cinema_data = EcCinemaIdsSerializer(ec_cinema_info).data
cinema_ip = ec_cinema_data.get('cinema_name')
cinema_info = Cinema.objects.filter(ip=cinema_ip).first()
cinema_data = CinemaSerializer(cinema_info).data
cinema_db = {
'host': cinema_data.get('ip'),
'user': cinema_data.get('db_user'),
'password': cinema_data.get('db_pwd'),
'port': 3306,
'database': 'cine'
}
quan = GetQuan(cinema_db)
quan_data = {
'quan': quan.get_quan(),
'card_quan': quan.get_card_quan(card_num) if card_num else []
}
return JsonResponse(quan_data)
# 对外接口,用于给前端提供上次请求的数据,如果没有则返回数据库中的默认值
# 若果有些字段是依赖于其他接口返回值生成的则单独处理此接口, 单独处理逻辑在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