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.
302 lines
9.8 KiB
302 lines
9.8 KiB
import datetime |
|
import json |
|
import re |
|
|
|
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.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 |
|
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.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) |
|
|
|
|
|
# 外部接口, 用于实时生成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() |
|
|
|
# 记录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, |
|
'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) |
|
|
|
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, |
|
'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
|
|
|